<!DOCTYPE html>
<html lang="en-US">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <title>快速部署微服务项目，保姆级教程 | 鱼皮的编程宝典</title>
    <meta name="generator" content="VuePress 1.9.10">
    <link rel="icon" href="/favicon.ico">
    <script>
        var _hmt = _hmt || [];
        (function() {
          var hm = document.createElement("script");
          hm.src = "https://hm.baidu.com/hm.js?2675818a983a3131404cee835018f016";
          var s = document.getElementsByTagName("script")[0]; 
          s.parentNode.insertBefore(hm, s);
        })();
      </script>
    <meta name="description" content="贴心的编程学习路线，全面的编程知识百科">
    <meta property="article:modified_time" content="2023-11-11T12:17:47.000Z">
    <meta property="og:site_name" content="鱼皮的编程宝典">
    <meta property="og:title" content="快速部署微服务项目，保姆级教程">
    <meta property="og:type" content="article">
    <meta property="og:url" content="https://codefather.cn/%E5%BF%AB%E9%80%9F%E9%83%A8%E7%BD%B2%E5%BE%AE%E6%9C%8D%E5%8A%A1%E9%A1%B9%E7%9B%AE-%E4%BF%9D%E5%A7%86%E7%BA%A7%E6%95%99%E7%A8%8B/">
    <meta name="twitter:title" content="快速部署微服务项目，保姆级教程">
    <meta name="twitter:url" content="https://codefather.cn/%E5%BF%AB%E9%80%9F%E9%83%A8%E7%BD%B2%E5%BE%AE%E6%9C%8D%E5%8A%A1%E9%A1%B9%E7%9B%AE-%E4%BF%9D%E5%A7%86%E7%BA%A7%E6%95%99%E7%A8%8B/">
    <meta name="twitter:card" content="summary_large_image">
    <meta name="twitter:label1" content="Written by">
    <meta name="twitter:label2" content="Filed under">
    <meta name="twitter:data2" content="程序员, 编程, 计算机">
    <meta property="article:tag" content="程序员">
    <meta name="keywords" content="程序员鱼皮, 编程学习路线, 编程知识百科, Java, 编程导航, 前端, 开发, 编程分享, 项目, IT, 求职, 面经">
    
    <link rel="preload" href="/assets/css/0.styles.40c15e22.css" as="style"><link rel="preload" href="/assets/js/app.12ab4756.js" as="script"><link rel="preload" href="/assets/js/2.fd06b53e.js" as="script"><link rel="preload" href="/assets/js/265.be8d1ee8.js" as="script"><link rel="prefetch" href="/assets/js/1.17ea1209.js"><link rel="prefetch" href="/assets/js/10.d9532d8f.js"><link rel="prefetch" href="/assets/js/100.064ea126.js"><link rel="prefetch" href="/assets/js/101.d64c5b33.js"><link rel="prefetch" href="/assets/js/102.5e29a62c.js"><link rel="prefetch" href="/assets/js/103.59ad6cd7.js"><link rel="prefetch" href="/assets/js/104.ae4763e8.js"><link rel="prefetch" href="/assets/js/105.2a9124be.js"><link rel="prefetch" href="/assets/js/106.529bca07.js"><link rel="prefetch" href="/assets/js/107.c8671a0d.js"><link rel="prefetch" href="/assets/js/108.55c93c64.js"><link rel="prefetch" href="/assets/js/109.7d1efa54.js"><link rel="prefetch" href="/assets/js/11.2f89b5eb.js"><link rel="prefetch" href="/assets/js/110.0caecbf5.js"><link rel="prefetch" href="/assets/js/111.a2aeae49.js"><link rel="prefetch" href="/assets/js/112.eb7ceda5.js"><link rel="prefetch" href="/assets/js/113.f304408d.js"><link rel="prefetch" href="/assets/js/114.988c637f.js"><link rel="prefetch" href="/assets/js/115.bfdeed31.js"><link rel="prefetch" href="/assets/js/116.a47b8c53.js"><link rel="prefetch" href="/assets/js/117.2e1e8250.js"><link rel="prefetch" href="/assets/js/118.758ce408.js"><link rel="prefetch" href="/assets/js/119.73d9e688.js"><link rel="prefetch" href="/assets/js/12.53aaa509.js"><link rel="prefetch" href="/assets/js/120.202a8b2e.js"><link rel="prefetch" href="/assets/js/121.ca91d59a.js"><link rel="prefetch" href="/assets/js/122.8804c0dd.js"><link rel="prefetch" href="/assets/js/123.ceada225.js"><link rel="prefetch" href="/assets/js/124.4b2718b7.js"><link rel="prefetch" href="/assets/js/125.72134235.js"><link rel="prefetch" href="/assets/js/126.167b162c.js"><link rel="prefetch" href="/assets/js/127.f8139c17.js"><link rel="prefetch" href="/assets/js/128.da64a377.js"><link rel="prefetch" href="/assets/js/129.c07963b1.js"><link rel="prefetch" href="/assets/js/13.52940164.js"><link rel="prefetch" href="/assets/js/130.f66fc8bb.js"><link rel="prefetch" href="/assets/js/131.a913c7dd.js"><link rel="prefetch" href="/assets/js/132.ea648654.js"><link rel="prefetch" href="/assets/js/133.074ca70e.js"><link rel="prefetch" href="/assets/js/134.dc79ddd8.js"><link rel="prefetch" href="/assets/js/135.c4516208.js"><link rel="prefetch" href="/assets/js/136.2546baf7.js"><link rel="prefetch" href="/assets/js/137.56454fc6.js"><link rel="prefetch" href="/assets/js/138.bdb002bf.js"><link rel="prefetch" href="/assets/js/139.40a2f9b5.js"><link rel="prefetch" href="/assets/js/14.ade1e74d.js"><link rel="prefetch" href="/assets/js/140.06b20427.js"><link rel="prefetch" href="/assets/js/141.8dd992e3.js"><link rel="prefetch" href="/assets/js/142.d9305485.js"><link rel="prefetch" href="/assets/js/143.41bf907e.js"><link rel="prefetch" href="/assets/js/144.c138960c.js"><link rel="prefetch" href="/assets/js/145.fc5b38c8.js"><link rel="prefetch" href="/assets/js/146.c9166b70.js"><link rel="prefetch" href="/assets/js/147.c31d8a01.js"><link rel="prefetch" href="/assets/js/148.5c0534ca.js"><link rel="prefetch" href="/assets/js/149.d2355ea2.js"><link rel="prefetch" href="/assets/js/15.970a8ca5.js"><link rel="prefetch" href="/assets/js/150.c1644898.js"><link rel="prefetch" href="/assets/js/151.b6e4adf0.js"><link rel="prefetch" href="/assets/js/152.7a5071aa.js"><link rel="prefetch" href="/assets/js/153.31abbc68.js"><link rel="prefetch" href="/assets/js/154.9c6bb079.js"><link rel="prefetch" href="/assets/js/155.e5506a40.js"><link rel="prefetch" href="/assets/js/156.992dab50.js"><link rel="prefetch" href="/assets/js/157.12a6ee84.js"><link rel="prefetch" href="/assets/js/158.84dc1045.js"><link rel="prefetch" href="/assets/js/159.fd2022b1.js"><link rel="prefetch" href="/assets/js/16.ff971500.js"><link rel="prefetch" href="/assets/js/160.8d8889cd.js"><link rel="prefetch" href="/assets/js/161.31797def.js"><link rel="prefetch" href="/assets/js/162.bfae7a75.js"><link rel="prefetch" href="/assets/js/163.e5e8094d.js"><link rel="prefetch" href="/assets/js/164.870f212c.js"><link rel="prefetch" href="/assets/js/165.8da20a31.js"><link rel="prefetch" href="/assets/js/166.950a187d.js"><link rel="prefetch" href="/assets/js/167.fd042c52.js"><link rel="prefetch" href="/assets/js/168.7d9f058d.js"><link rel="prefetch" href="/assets/js/169.205df80e.js"><link rel="prefetch" href="/assets/js/17.4b045b26.js"><link rel="prefetch" href="/assets/js/170.270108a3.js"><link rel="prefetch" href="/assets/js/171.9f03d27d.js"><link rel="prefetch" href="/assets/js/172.1882bac7.js"><link rel="prefetch" href="/assets/js/173.fc1fe7d4.js"><link rel="prefetch" href="/assets/js/174.d77c927b.js"><link rel="prefetch" href="/assets/js/175.019b9e83.js"><link rel="prefetch" href="/assets/js/176.5ce31bd8.js"><link rel="prefetch" href="/assets/js/177.9a2006f2.js"><link rel="prefetch" href="/assets/js/178.88265ac1.js"><link rel="prefetch" href="/assets/js/179.3205ce07.js"><link rel="prefetch" href="/assets/js/18.1cdd0514.js"><link rel="prefetch" href="/assets/js/180.2ff51f44.js"><link rel="prefetch" href="/assets/js/181.f792ce97.js"><link rel="prefetch" href="/assets/js/182.103328e1.js"><link rel="prefetch" href="/assets/js/183.40fde303.js"><link rel="prefetch" href="/assets/js/184.1f36ac78.js"><link rel="prefetch" href="/assets/js/185.cf3b1c00.js"><link rel="prefetch" href="/assets/js/186.f7981399.js"><link rel="prefetch" href="/assets/js/187.20fe296d.js"><link rel="prefetch" href="/assets/js/188.7b004fea.js"><link rel="prefetch" href="/assets/js/189.599ca2d9.js"><link rel="prefetch" href="/assets/js/19.5740e4d6.js"><link rel="prefetch" href="/assets/js/190.14087c07.js"><link rel="prefetch" href="/assets/js/191.b0f73f6d.js"><link rel="prefetch" href="/assets/js/192.9d171669.js"><link rel="prefetch" href="/assets/js/193.00975585.js"><link rel="prefetch" href="/assets/js/194.2c7c43b4.js"><link rel="prefetch" href="/assets/js/195.ff126254.js"><link rel="prefetch" href="/assets/js/196.6546ae1c.js"><link rel="prefetch" href="/assets/js/197.eedb67bb.js"><link rel="prefetch" href="/assets/js/198.acdcc22c.js"><link rel="prefetch" href="/assets/js/199.7993a6b2.js"><link rel="prefetch" href="/assets/js/20.8885a4fa.js"><link rel="prefetch" href="/assets/js/200.52f08765.js"><link rel="prefetch" href="/assets/js/201.b85ab10b.js"><link rel="prefetch" href="/assets/js/202.ccec1c85.js"><link rel="prefetch" href="/assets/js/203.3f50a6ed.js"><link rel="prefetch" href="/assets/js/204.f28b803b.js"><link rel="prefetch" href="/assets/js/205.c51c53fd.js"><link rel="prefetch" href="/assets/js/206.ba0aa8f6.js"><link rel="prefetch" href="/assets/js/207.0dce311a.js"><link rel="prefetch" href="/assets/js/208.0ea629a6.js"><link rel="prefetch" href="/assets/js/209.f48c3e71.js"><link rel="prefetch" href="/assets/js/21.0bb62db4.js"><link rel="prefetch" href="/assets/js/210.689db8f2.js"><link rel="prefetch" href="/assets/js/211.72bc0f1f.js"><link rel="prefetch" href="/assets/js/212.456135bd.js"><link rel="prefetch" href="/assets/js/213.d0ea50fc.js"><link rel="prefetch" href="/assets/js/214.1400da91.js"><link rel="prefetch" href="/assets/js/215.aeef3e5d.js"><link rel="prefetch" href="/assets/js/216.a60215af.js"><link rel="prefetch" href="/assets/js/217.d6cd8b69.js"><link rel="prefetch" href="/assets/js/218.1bd500fc.js"><link rel="prefetch" href="/assets/js/219.20faf611.js"><link rel="prefetch" href="/assets/js/22.3e8347a6.js"><link rel="prefetch" href="/assets/js/220.6714179b.js"><link rel="prefetch" href="/assets/js/221.fb5b643d.js"><link rel="prefetch" href="/assets/js/222.d96272e5.js"><link rel="prefetch" href="/assets/js/223.4cb7dc3d.js"><link rel="prefetch" href="/assets/js/224.500d94cc.js"><link rel="prefetch" href="/assets/js/225.d006c34e.js"><link rel="prefetch" href="/assets/js/226.73612150.js"><link rel="prefetch" href="/assets/js/227.b02db9d1.js"><link rel="prefetch" href="/assets/js/228.aad43ff2.js"><link rel="prefetch" href="/assets/js/229.65340802.js"><link rel="prefetch" href="/assets/js/23.ceb5a5ff.js"><link rel="prefetch" href="/assets/js/230.97cab104.js"><link rel="prefetch" href="/assets/js/231.8415349a.js"><link rel="prefetch" href="/assets/js/232.db6d2697.js"><link rel="prefetch" href="/assets/js/233.723d05b1.js"><link rel="prefetch" href="/assets/js/234.26ed5e94.js"><link rel="prefetch" href="/assets/js/235.a586122b.js"><link rel="prefetch" href="/assets/js/236.f802bda8.js"><link rel="prefetch" href="/assets/js/237.cc8767ad.js"><link rel="prefetch" href="/assets/js/238.6485459e.js"><link rel="prefetch" href="/assets/js/239.9fbf3a55.js"><link rel="prefetch" href="/assets/js/24.07267ac6.js"><link rel="prefetch" href="/assets/js/240.1188f244.js"><link rel="prefetch" href="/assets/js/241.cbfb154d.js"><link rel="prefetch" href="/assets/js/242.352cea5a.js"><link rel="prefetch" href="/assets/js/243.07947e1c.js"><link rel="prefetch" href="/assets/js/244.f5b26fa9.js"><link rel="prefetch" href="/assets/js/245.c6030e32.js"><link rel="prefetch" href="/assets/js/246.d3fe99f7.js"><link rel="prefetch" href="/assets/js/247.185ae95d.js"><link rel="prefetch" href="/assets/js/248.a5f1548c.js"><link rel="prefetch" href="/assets/js/249.19691113.js"><link rel="prefetch" href="/assets/js/25.15e1f641.js"><link rel="prefetch" href="/assets/js/250.72fa1d33.js"><link rel="prefetch" href="/assets/js/251.bedd56f7.js"><link rel="prefetch" href="/assets/js/252.32bbcc8b.js"><link rel="prefetch" href="/assets/js/253.b59e5846.js"><link rel="prefetch" href="/assets/js/254.c0e37e1a.js"><link rel="prefetch" href="/assets/js/255.850da3cc.js"><link rel="prefetch" href="/assets/js/256.952d9817.js"><link rel="prefetch" href="/assets/js/257.88667bb8.js"><link rel="prefetch" href="/assets/js/258.c5873c28.js"><link rel="prefetch" href="/assets/js/259.6ae1dcbc.js"><link rel="prefetch" href="/assets/js/26.35b2bbdc.js"><link rel="prefetch" href="/assets/js/260.cb940cc3.js"><link rel="prefetch" href="/assets/js/261.0686c3e9.js"><link rel="prefetch" href="/assets/js/262.d0719839.js"><link rel="prefetch" href="/assets/js/263.ae83ebc1.js"><link rel="prefetch" href="/assets/js/264.209ad8a3.js"><link rel="prefetch" href="/assets/js/266.c51bceaa.js"><link rel="prefetch" href="/assets/js/267.fe8af48a.js"><link rel="prefetch" href="/assets/js/268.e18ed861.js"><link rel="prefetch" href="/assets/js/269.7126031e.js"><link rel="prefetch" href="/assets/js/27.270fcb06.js"><link rel="prefetch" href="/assets/js/270.89ead106.js"><link rel="prefetch" href="/assets/js/271.0643d07a.js"><link rel="prefetch" href="/assets/js/272.32a8e4b0.js"><link rel="prefetch" href="/assets/js/273.9881da47.js"><link rel="prefetch" href="/assets/js/274.2de022ea.js"><link rel="prefetch" href="/assets/js/275.d9a4fe99.js"><link rel="prefetch" href="/assets/js/276.d33de2e9.js"><link rel="prefetch" href="/assets/js/277.1ec367ab.js"><link rel="prefetch" href="/assets/js/278.66ab7c11.js"><link rel="prefetch" href="/assets/js/279.ff51cd15.js"><link rel="prefetch" href="/assets/js/28.ef3f6db2.js"><link rel="prefetch" href="/assets/js/280.ef45ed5f.js"><link rel="prefetch" href="/assets/js/281.87f26b81.js"><link rel="prefetch" href="/assets/js/282.c8ef594b.js"><link rel="prefetch" href="/assets/js/283.15643091.js"><link rel="prefetch" href="/assets/js/284.c4f25b2e.js"><link rel="prefetch" href="/assets/js/285.2d16e4b6.js"><link rel="prefetch" href="/assets/js/286.44eba266.js"><link rel="prefetch" href="/assets/js/287.7613e62f.js"><link rel="prefetch" href="/assets/js/288.b9546d55.js"><link rel="prefetch" href="/assets/js/289.125f85d8.js"><link rel="prefetch" href="/assets/js/29.177558be.js"><link rel="prefetch" href="/assets/js/290.db375797.js"><link rel="prefetch" href="/assets/js/291.90946626.js"><link rel="prefetch" href="/assets/js/292.a4524678.js"><link rel="prefetch" href="/assets/js/293.3ed9b083.js"><link rel="prefetch" href="/assets/js/294.d6c14116.js"><link rel="prefetch" href="/assets/js/295.2b485032.js"><link rel="prefetch" href="/assets/js/296.29d9aa0f.js"><link rel="prefetch" href="/assets/js/297.bfd72435.js"><link rel="prefetch" href="/assets/js/298.fc056989.js"><link rel="prefetch" href="/assets/js/299.0a3f258e.js"><link rel="prefetch" href="/assets/js/3.4dc033c7.js"><link rel="prefetch" href="/assets/js/30.248a229d.js"><link rel="prefetch" href="/assets/js/300.d064d776.js"><link rel="prefetch" href="/assets/js/301.d95b9fc0.js"><link rel="prefetch" href="/assets/js/302.1afa637a.js"><link rel="prefetch" href="/assets/js/303.231beaa8.js"><link rel="prefetch" href="/assets/js/304.05df35d9.js"><link rel="prefetch" href="/assets/js/305.f2d83cf9.js"><link rel="prefetch" href="/assets/js/306.d54f5e5e.js"><link rel="prefetch" href="/assets/js/307.d5df9000.js"><link rel="prefetch" href="/assets/js/308.ef2f52b3.js"><link rel="prefetch" href="/assets/js/309.d1f13319.js"><link rel="prefetch" href="/assets/js/31.32a62b91.js"><link rel="prefetch" href="/assets/js/310.30b84be3.js"><link rel="prefetch" href="/assets/js/311.d79e3145.js"><link rel="prefetch" href="/assets/js/312.58e24f19.js"><link rel="prefetch" href="/assets/js/313.9809a122.js"><link rel="prefetch" href="/assets/js/314.e92e41b1.js"><link rel="prefetch" href="/assets/js/315.8c2fc1d4.js"><link rel="prefetch" href="/assets/js/316.a0904343.js"><link rel="prefetch" href="/assets/js/317.18e42b54.js"><link rel="prefetch" href="/assets/js/318.6b051d27.js"><link rel="prefetch" href="/assets/js/319.513b0197.js"><link rel="prefetch" href="/assets/js/32.23b75afc.js"><link rel="prefetch" href="/assets/js/320.ae91bc36.js"><link rel="prefetch" href="/assets/js/321.a194efea.js"><link rel="prefetch" href="/assets/js/322.8273020e.js"><link rel="prefetch" href="/assets/js/323.d332e08f.js"><link rel="prefetch" href="/assets/js/324.ed867b64.js"><link rel="prefetch" href="/assets/js/325.c43ccf9a.js"><link rel="prefetch" href="/assets/js/326.9497d879.js"><link rel="prefetch" href="/assets/js/327.7f095e40.js"><link rel="prefetch" href="/assets/js/328.cb5c5847.js"><link rel="prefetch" href="/assets/js/329.d36b59f3.js"><link rel="prefetch" href="/assets/js/33.b258b779.js"><link rel="prefetch" href="/assets/js/330.b1a092b9.js"><link rel="prefetch" href="/assets/js/331.ff86566f.js"><link rel="prefetch" href="/assets/js/332.0daafa9f.js"><link rel="prefetch" href="/assets/js/333.b7e50524.js"><link rel="prefetch" href="/assets/js/334.7dcf9f0b.js"><link rel="prefetch" href="/assets/js/335.862c410a.js"><link rel="prefetch" href="/assets/js/336.c6384990.js"><link rel="prefetch" href="/assets/js/337.ab9d5e52.js"><link rel="prefetch" href="/assets/js/338.598ae59e.js"><link rel="prefetch" href="/assets/js/339.9b810ff8.js"><link rel="prefetch" href="/assets/js/34.3bd60f1f.js"><link rel="prefetch" href="/assets/js/340.5609a53c.js"><link rel="prefetch" href="/assets/js/341.969d335a.js"><link rel="prefetch" href="/assets/js/342.43f85dba.js"><link rel="prefetch" href="/assets/js/343.47280ef9.js"><link rel="prefetch" href="/assets/js/344.346ae5fc.js"><link rel="prefetch" href="/assets/js/345.32166361.js"><link rel="prefetch" href="/assets/js/346.86ff128b.js"><link rel="prefetch" href="/assets/js/347.3c5421fe.js"><link rel="prefetch" href="/assets/js/348.95910300.js"><link rel="prefetch" href="/assets/js/349.004158d8.js"><link rel="prefetch" href="/assets/js/35.18e8f66a.js"><link rel="prefetch" href="/assets/js/350.e10b195b.js"><link rel="prefetch" href="/assets/js/351.12f89875.js"><link rel="prefetch" href="/assets/js/352.83957394.js"><link rel="prefetch" href="/assets/js/353.475971b9.js"><link rel="prefetch" href="/assets/js/354.8af7b26b.js"><link rel="prefetch" href="/assets/js/355.85925e24.js"><link rel="prefetch" href="/assets/js/356.1d77cf9c.js"><link rel="prefetch" href="/assets/js/357.b467d481.js"><link rel="prefetch" href="/assets/js/358.ac96f32d.js"><link rel="prefetch" href="/assets/js/359.e048bd10.js"><link rel="prefetch" href="/assets/js/36.a7ae257c.js"><link rel="prefetch" href="/assets/js/360.e9b45545.js"><link rel="prefetch" href="/assets/js/361.ad1bb45b.js"><link rel="prefetch" href="/assets/js/362.4e24a30b.js"><link rel="prefetch" href="/assets/js/363.64f7dad5.js"><link rel="prefetch" href="/assets/js/364.d9e3ebc2.js"><link rel="prefetch" href="/assets/js/365.330e3086.js"><link rel="prefetch" href="/assets/js/366.a6c0afb3.js"><link rel="prefetch" href="/assets/js/367.ffcefa40.js"><link rel="prefetch" href="/assets/js/368.664c8e4d.js"><link rel="prefetch" href="/assets/js/369.67da2dd2.js"><link rel="prefetch" href="/assets/js/37.d709f9a9.js"><link rel="prefetch" href="/assets/js/370.b1791970.js"><link rel="prefetch" href="/assets/js/371.743a461a.js"><link rel="prefetch" href="/assets/js/372.7703ef1b.js"><link rel="prefetch" href="/assets/js/373.17de31f6.js"><link rel="prefetch" href="/assets/js/374.e508be9e.js"><link rel="prefetch" href="/assets/js/375.6e2e9fe3.js"><link rel="prefetch" href="/assets/js/376.8ca3511a.js"><link rel="prefetch" href="/assets/js/377.bfcee39c.js"><link rel="prefetch" href="/assets/js/378.21852b78.js"><link rel="prefetch" href="/assets/js/379.9649c307.js"><link rel="prefetch" href="/assets/js/38.68ca920e.js"><link rel="prefetch" href="/assets/js/380.dadb4418.js"><link rel="prefetch" href="/assets/js/381.a03c993d.js"><link rel="prefetch" href="/assets/js/382.bb7c22c1.js"><link rel="prefetch" href="/assets/js/383.bd68b2e5.js"><link rel="prefetch" href="/assets/js/384.f6dc7457.js"><link rel="prefetch" href="/assets/js/385.14287a91.js"><link rel="prefetch" href="/assets/js/386.a6284ac2.js"><link rel="prefetch" href="/assets/js/387.c51f147a.js"><link rel="prefetch" href="/assets/js/388.06d9651e.js"><link rel="prefetch" href="/assets/js/389.2d85d927.js"><link rel="prefetch" href="/assets/js/39.de850db9.js"><link rel="prefetch" href="/assets/js/390.2397b3e0.js"><link rel="prefetch" href="/assets/js/391.8413aaaf.js"><link rel="prefetch" href="/assets/js/392.00eecaa4.js"><link rel="prefetch" href="/assets/js/393.351dd3fd.js"><link rel="prefetch" href="/assets/js/394.d2cc4a70.js"><link rel="prefetch" href="/assets/js/395.abee64bf.js"><link rel="prefetch" href="/assets/js/396.bc265e6a.js"><link rel="prefetch" href="/assets/js/397.e4a96944.js"><link rel="prefetch" href="/assets/js/398.f0d26b29.js"><link rel="prefetch" href="/assets/js/399.e77c3ddc.js"><link rel="prefetch" href="/assets/js/4.2f502b73.js"><link rel="prefetch" href="/assets/js/40.91635261.js"><link rel="prefetch" href="/assets/js/400.c7eac401.js"><link rel="prefetch" href="/assets/js/401.06092d16.js"><link rel="prefetch" href="/assets/js/402.4e08e496.js"><link rel="prefetch" href="/assets/js/403.deba4c77.js"><link rel="prefetch" href="/assets/js/404.9100e4df.js"><link rel="prefetch" href="/assets/js/405.e9f451e2.js"><link rel="prefetch" href="/assets/js/406.a0da4aa4.js"><link rel="prefetch" href="/assets/js/407.58b2b123.js"><link rel="prefetch" href="/assets/js/408.eb2cde2d.js"><link rel="prefetch" href="/assets/js/409.9041f749.js"><link rel="prefetch" href="/assets/js/41.169a3cfc.js"><link rel="prefetch" href="/assets/js/410.c12f3710.js"><link rel="prefetch" href="/assets/js/411.452cda45.js"><link rel="prefetch" href="/assets/js/412.8691317a.js"><link rel="prefetch" href="/assets/js/413.25a68f21.js"><link rel="prefetch" href="/assets/js/414.7a9699d8.js"><link rel="prefetch" href="/assets/js/415.6e8cdaff.js"><link rel="prefetch" href="/assets/js/416.e8a86529.js"><link rel="prefetch" href="/assets/js/417.28330bde.js"><link rel="prefetch" href="/assets/js/418.2fed8e17.js"><link rel="prefetch" href="/assets/js/419.773032f4.js"><link rel="prefetch" href="/assets/js/42.e17cd061.js"><link rel="prefetch" href="/assets/js/420.56681228.js"><link rel="prefetch" href="/assets/js/421.0d170e13.js"><link rel="prefetch" href="/assets/js/422.fc8c2a11.js"><link rel="prefetch" href="/assets/js/423.e34ea6a6.js"><link rel="prefetch" href="/assets/js/424.20fe8748.js"><link rel="prefetch" href="/assets/js/425.f001b7cd.js"><link rel="prefetch" href="/assets/js/426.a91230ef.js"><link rel="prefetch" href="/assets/js/427.c6c9fe8d.js"><link rel="prefetch" href="/assets/js/428.9d4f5e41.js"><link rel="prefetch" href="/assets/js/429.c81cfd3f.js"><link rel="prefetch" href="/assets/js/43.f88aa667.js"><link rel="prefetch" href="/assets/js/430.eb61372f.js"><link rel="prefetch" href="/assets/js/431.4a25365a.js"><link rel="prefetch" href="/assets/js/432.42fc1bbe.js"><link rel="prefetch" href="/assets/js/433.8e9ac9f0.js"><link rel="prefetch" href="/assets/js/434.fdd0b160.js"><link rel="prefetch" href="/assets/js/435.d6cbac31.js"><link rel="prefetch" href="/assets/js/436.17750ba2.js"><link rel="prefetch" href="/assets/js/437.a1468099.js"><link rel="prefetch" href="/assets/js/438.ac6a45c2.js"><link rel="prefetch" href="/assets/js/439.242ae27a.js"><link rel="prefetch" href="/assets/js/44.3f36e228.js"><link rel="prefetch" href="/assets/js/440.b80b520c.js"><link rel="prefetch" href="/assets/js/441.e51a4bbb.js"><link rel="prefetch" href="/assets/js/442.ab0b3eda.js"><link rel="prefetch" href="/assets/js/443.47e44250.js"><link rel="prefetch" href="/assets/js/444.54c3b425.js"><link rel="prefetch" href="/assets/js/445.e006c12e.js"><link rel="prefetch" href="/assets/js/446.f2b79730.js"><link rel="prefetch" href="/assets/js/447.2509a397.js"><link rel="prefetch" href="/assets/js/448.b7d69dfc.js"><link rel="prefetch" href="/assets/js/449.8a575d9b.js"><link rel="prefetch" href="/assets/js/45.be1455b1.js"><link rel="prefetch" href="/assets/js/450.ad421aeb.js"><link rel="prefetch" href="/assets/js/451.f09912ae.js"><link rel="prefetch" href="/assets/js/452.f528c4ce.js"><link rel="prefetch" href="/assets/js/453.fc4dc0f9.js"><link rel="prefetch" href="/assets/js/454.733c315c.js"><link rel="prefetch" href="/assets/js/455.44fe35b1.js"><link rel="prefetch" href="/assets/js/456.7f650035.js"><link rel="prefetch" href="/assets/js/457.77ebc183.js"><link rel="prefetch" href="/assets/js/458.133078f4.js"><link rel="prefetch" href="/assets/js/459.33728b5e.js"><link rel="prefetch" href="/assets/js/46.5ad74cb5.js"><link rel="prefetch" href="/assets/js/460.6946f564.js"><link rel="prefetch" href="/assets/js/461.6f906c5c.js"><link rel="prefetch" href="/assets/js/462.26eca27e.js"><link rel="prefetch" href="/assets/js/463.e02e5f65.js"><link rel="prefetch" href="/assets/js/464.0df25c63.js"><link rel="prefetch" href="/assets/js/465.80cd249e.js"><link rel="prefetch" href="/assets/js/466.a0921e86.js"><link rel="prefetch" href="/assets/js/467.1bec2b47.js"><link rel="prefetch" href="/assets/js/468.b6fa37c1.js"><link rel="prefetch" href="/assets/js/469.a1d2487e.js"><link rel="prefetch" href="/assets/js/47.03df5d0a.js"><link rel="prefetch" href="/assets/js/470.36a4b9c8.js"><link rel="prefetch" href="/assets/js/471.28895273.js"><link rel="prefetch" href="/assets/js/472.b9fe392f.js"><link rel="prefetch" href="/assets/js/473.a2835d9c.js"><link rel="prefetch" href="/assets/js/474.cd57b37d.js"><link rel="prefetch" href="/assets/js/475.8d5a9792.js"><link rel="prefetch" href="/assets/js/476.f7f3781c.js"><link rel="prefetch" href="/assets/js/477.9b710b04.js"><link rel="prefetch" href="/assets/js/478.46d66687.js"><link rel="prefetch" href="/assets/js/479.e7444705.js"><link rel="prefetch" href="/assets/js/48.48f286ba.js"><link rel="prefetch" href="/assets/js/480.da2b750a.js"><link rel="prefetch" href="/assets/js/481.838a8e04.js"><link rel="prefetch" href="/assets/js/482.02bf8041.js"><link rel="prefetch" href="/assets/js/483.bb29ef2f.js"><link rel="prefetch" href="/assets/js/484.aebb68bd.js"><link rel="prefetch" href="/assets/js/485.a66ab41b.js"><link rel="prefetch" href="/assets/js/486.8df516fb.js"><link rel="prefetch" href="/assets/js/487.86d28130.js"><link rel="prefetch" href="/assets/js/488.0863da70.js"><link rel="prefetch" href="/assets/js/489.5d4d9e88.js"><link rel="prefetch" href="/assets/js/49.1ca52d11.js"><link rel="prefetch" href="/assets/js/490.3fd65d85.js"><link rel="prefetch" href="/assets/js/491.ae3a2f87.js"><link rel="prefetch" href="/assets/js/492.6f54679b.js"><link rel="prefetch" href="/assets/js/493.a594b1f4.js"><link rel="prefetch" href="/assets/js/494.4f03fae1.js"><link rel="prefetch" href="/assets/js/495.ae50b66b.js"><link rel="prefetch" href="/assets/js/496.bc92d835.js"><link rel="prefetch" href="/assets/js/497.eac65251.js"><link rel="prefetch" href="/assets/js/498.1d726726.js"><link rel="prefetch" href="/assets/js/499.01e4f7d1.js"><link rel="prefetch" href="/assets/js/5.7b1f056c.js"><link rel="prefetch" href="/assets/js/50.73732fe2.js"><link rel="prefetch" href="/assets/js/500.062ade4e.js"><link rel="prefetch" href="/assets/js/501.e6a711dc.js"><link rel="prefetch" href="/assets/js/502.c79e28e2.js"><link rel="prefetch" href="/assets/js/503.bf97bce9.js"><link rel="prefetch" href="/assets/js/504.b2784ef0.js"><link rel="prefetch" href="/assets/js/505.0767ba54.js"><link rel="prefetch" href="/assets/js/506.8ae14637.js"><link rel="prefetch" href="/assets/js/507.003e2349.js"><link rel="prefetch" href="/assets/js/508.ecb5e6bd.js"><link rel="prefetch" href="/assets/js/509.b644f44a.js"><link rel="prefetch" href="/assets/js/51.bed7cf61.js"><link rel="prefetch" href="/assets/js/510.b660946f.js"><link rel="prefetch" href="/assets/js/511.cb186c8f.js"><link rel="prefetch" href="/assets/js/512.d176170f.js"><link rel="prefetch" href="/assets/js/513.18a1afa5.js"><link rel="prefetch" href="/assets/js/514.4a33e931.js"><link rel="prefetch" href="/assets/js/515.8496bd4d.js"><link rel="prefetch" href="/assets/js/516.529b9476.js"><link rel="prefetch" href="/assets/js/517.289738f1.js"><link rel="prefetch" href="/assets/js/518.eda39556.js"><link rel="prefetch" href="/assets/js/519.85b42de5.js"><link rel="prefetch" href="/assets/js/52.22a7da62.js"><link rel="prefetch" href="/assets/js/520.8b531775.js"><link rel="prefetch" href="/assets/js/521.8e4b66fb.js"><link rel="prefetch" href="/assets/js/522.050bfc55.js"><link rel="prefetch" href="/assets/js/523.e973f1e0.js"><link rel="prefetch" href="/assets/js/524.fd160738.js"><link rel="prefetch" href="/assets/js/525.5a4bc307.js"><link rel="prefetch" href="/assets/js/526.361bc4fa.js"><link rel="prefetch" href="/assets/js/527.06ee9d73.js"><link rel="prefetch" href="/assets/js/528.22d9b118.js"><link rel="prefetch" href="/assets/js/529.b7592c16.js"><link rel="prefetch" href="/assets/js/53.767f3bbf.js"><link rel="prefetch" href="/assets/js/530.ad96d564.js"><link rel="prefetch" href="/assets/js/531.61905243.js"><link rel="prefetch" href="/assets/js/532.11aebf61.js"><link rel="prefetch" href="/assets/js/533.0cddb226.js"><link rel="prefetch" href="/assets/js/534.d1c9cc36.js"><link rel="prefetch" href="/assets/js/54.d1f9eec8.js"><link rel="prefetch" href="/assets/js/55.aa90e812.js"><link rel="prefetch" href="/assets/js/56.4d7f81f2.js"><link rel="prefetch" href="/assets/js/57.3c540e8d.js"><link rel="prefetch" href="/assets/js/58.fc1c23f2.js"><link rel="prefetch" href="/assets/js/59.c7a7a4c0.js"><link rel="prefetch" href="/assets/js/6.056886f1.js"><link rel="prefetch" href="/assets/js/60.40e590ae.js"><link rel="prefetch" href="/assets/js/61.e400b323.js"><link rel="prefetch" href="/assets/js/62.bbb30ef1.js"><link rel="prefetch" href="/assets/js/63.c31cd2bb.js"><link rel="prefetch" href="/assets/js/64.62321188.js"><link rel="prefetch" href="/assets/js/65.44adc2b3.js"><link rel="prefetch" href="/assets/js/66.b5740d4f.js"><link rel="prefetch" href="/assets/js/67.76c3624c.js"><link rel="prefetch" href="/assets/js/68.6dd982d4.js"><link rel="prefetch" href="/assets/js/69.eb1390ec.js"><link rel="prefetch" href="/assets/js/7.a96cecf9.js"><link rel="prefetch" href="/assets/js/70.8c882bdd.js"><link rel="prefetch" href="/assets/js/71.001c968a.js"><link rel="prefetch" href="/assets/js/72.ae4ca075.js"><link rel="prefetch" href="/assets/js/73.d6ae6a27.js"><link rel="prefetch" href="/assets/js/74.fba60e37.js"><link rel="prefetch" href="/assets/js/75.0b1bf7bf.js"><link rel="prefetch" href="/assets/js/76.ee19d90e.js"><link rel="prefetch" href="/assets/js/77.fe8ac5f0.js"><link rel="prefetch" href="/assets/js/78.ae09432e.js"><link rel="prefetch" href="/assets/js/79.c1b10e2d.js"><link rel="prefetch" href="/assets/js/80.ae809538.js"><link rel="prefetch" href="/assets/js/81.ca11b4c7.js"><link rel="prefetch" href="/assets/js/82.308b98e4.js"><link rel="prefetch" href="/assets/js/83.355d9dde.js"><link rel="prefetch" href="/assets/js/84.a2b61d48.js"><link rel="prefetch" href="/assets/js/85.cf992fda.js"><link rel="prefetch" href="/assets/js/86.f547c7ea.js"><link rel="prefetch" href="/assets/js/87.2b02746a.js"><link rel="prefetch" href="/assets/js/88.e939aad5.js"><link rel="prefetch" href="/assets/js/89.b000c42a.js"><link rel="prefetch" href="/assets/js/90.dadef001.js"><link rel="prefetch" href="/assets/js/91.c0fe2e32.js"><link rel="prefetch" href="/assets/js/92.e09650b9.js"><link rel="prefetch" href="/assets/js/93.427c7280.js"><link rel="prefetch" href="/assets/js/94.90fc5f58.js"><link rel="prefetch" href="/assets/js/95.13d42b3a.js"><link rel="prefetch" href="/assets/js/96.d0a2ea8c.js"><link rel="prefetch" href="/assets/js/97.cc9a0eda.js"><link rel="prefetch" href="/assets/js/98.3c9f1b7e.js"><link rel="prefetch" href="/assets/js/99.0420dcbc.js"><link rel="prefetch" href="/assets/js/vendors~docsearch.33b2b47d.js">
    <link rel="stylesheet" href="/assets/css/0.styles.40c15e22.css">
  </head>
  <body>
    <div id="app" data-server-rendered="true"><div class="theme-container"><header class="navbar"><div class="sidebar-button"><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" role="img" viewBox="0 0 448 512" class="icon"><path fill="currentColor" d="M436 124H12c-6.627 0-12-5.373-12-12V80c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12z"></path></svg></div> <a href="/" class="home-link router-link-active"><img src="/logo.png" alt="鱼皮的编程宝典" class="logo"> <span class="site-name can-hide">鱼皮的编程宝典</span></a> <div class="links"><div class="search-box"><input aria-label="Search" autocomplete="off" spellcheck="false" value=""> <!----></div> <nav class="nav-links can-hide"><div class="nav-item"><a href="/学习路线/" class="nav-link">
  学习路线
</a></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="自学之路" class="dropdown-title"><span class="title">自学之路</span> <span class="arrow down"></span></button> <button type="button" aria-label="自学之路" class="mobile-dropdown-title"><span class="title">自学之路</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="/自学之路/#大学经历" class="nav-link">
  大学经历
</a></li><li class="dropdown-item"><!----> <a href="/自学之路/#求职经历" class="nav-link">
  求职经历
</a></li><li class="dropdown-item"><!----> <a href="/自学之路/#职场工作" class="nav-link">
  职场工作
</a></li><li class="dropdown-item"><!----> <a href="/自学之路/#创作经历" class="nav-link">
  创作经历
</a></li><li class="dropdown-item"><!----> <a href="/自学之路/#创业经历" class="nav-link">
  创业经历
</a></li><li class="dropdown-item"><!----> <a href="/自学之路/#生活日常" class="nav-link">
  生活日常
</a></li></ul></div></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="编程分享" class="dropdown-title"><span class="title">编程分享</span> <span class="arrow down"></span></button> <button type="button" aria-label="编程分享" class="mobile-dropdown-title"><span class="title">编程分享</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="/编程分享/#入门必看-学习路线" class="nav-link">
  入门必看-学习路线
</a></li><li class="dropdown-item"><!----> <a href="/编程分享/#学习指南" class="nav-link">
  学习指南
</a></li><li class="dropdown-item"><!----> <a href="/编程分享/#开发经验" class="nav-link">
  开发经验
</a></li><li class="dropdown-item"><!----> <a href="/编程分享/#求职经验" class="nav-link">
  求职经验
</a></li><li class="dropdown-item"><!----> <a href="/编程分享/#职场经验" class="nav-link">
  职场经验
</a></li><li class="dropdown-item"><!----> <a href="/编程分享/#技术分享" class="nav-link">
  技术分享
</a></li><li class="dropdown-item"><!----> <a href="/编程分享/#实战教程" class="nav-link">
  实战教程
</a></li><li class="dropdown-item"><!----> <a href="/编程分享/#其他" class="nav-link">
  其他
</a></li><li class="dropdown-item"><!----> <a href="/编程分享/#📚-项目教程" class="nav-link">
  项目教程
</a></li><li class="dropdown-item"><!----> <a href="/编程分享/#个人作品" class="nav-link">
  个人作品
</a></li><li class="dropdown-item"><!----> <a href="/编程分享/#🎁-编程资源" class="nav-link">
  编程资源
</a></li><li class="dropdown-item"><!----> <a href="/编程分享/#🌐-科技科普" class="nav-link">
  科技科普
</a></li></ul></div></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="项目实战" class="dropdown-title"><span class="title">项目实战</span> <span class="arrow down"></span></button> <button type="button" aria-label="项目实战" class="mobile-dropdown-title"><span class="title">项目实战</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="/项目实战/OJ 判题系统.html" class="nav-link">
  OJ 判题系统
</a></li><li class="dropdown-item"><!----> <a href="/项目实战/智能 BI 平台.html" class="nav-link">
  智能 BI 平台
</a></li><li class="dropdown-item"><!----> <a href="/项目实战/聚合搜索平台.html" class="nav-link">
  聚合搜索平台
</a></li><li class="dropdown-item"><!----> <a href="/项目实战/API 开放平台.html" class="nav-link">
  API 开放平台
</a></li><li class="dropdown-item"><!----> <a href="/项目实战/伙伴匹配系统.html" class="nav-link">
  伙伴匹配系统
</a></li><li class="dropdown-item"><!----> <a href="/项目实战/用户中心项目.html" class="nav-link">
  用户中心项目
</a></li><li class="dropdown-item"><!----> <a href="/项目实战/Java 后端万用项目模板.html" class="nav-link">
  Java 后端万用项目模板
</a></li></ul></div></div><div class="nav-item"><a href="/知识碎片/" class="nav-link">
  知识碎片
</a></div><div class="nav-item"><a href="/编程导航/" class="nav-link">
  🔥 编程导航
</a></div><div class="nav-item"><a href="/产品服务/" class="nav-link">
  产品服务
</a></div><div class="nav-item"><a href="/作者/" class="nav-link">
  作者
</a></div> <a href="https://github.com/liyupi/codefather" target="_blank" rel="noopener noreferrer" class="repo-link">
    GitHub
    <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></nav></div></header> <div class="sidebar-mask"></div> <aside class="sidebar"><nav class="nav-links"><div class="nav-item"><a href="/学习路线/" class="nav-link">
  学习路线
</a></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="自学之路" class="dropdown-title"><span class="title">自学之路</span> <span class="arrow down"></span></button> <button type="button" aria-label="自学之路" class="mobile-dropdown-title"><span class="title">自学之路</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="/自学之路/#大学经历" class="nav-link">
  大学经历
</a></li><li class="dropdown-item"><!----> <a href="/自学之路/#求职经历" class="nav-link">
  求职经历
</a></li><li class="dropdown-item"><!----> <a href="/自学之路/#职场工作" class="nav-link">
  职场工作
</a></li><li class="dropdown-item"><!----> <a href="/自学之路/#创作经历" class="nav-link">
  创作经历
</a></li><li class="dropdown-item"><!----> <a href="/自学之路/#创业经历" class="nav-link">
  创业经历
</a></li><li class="dropdown-item"><!----> <a href="/自学之路/#生活日常" class="nav-link">
  生活日常
</a></li></ul></div></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="编程分享" class="dropdown-title"><span class="title">编程分享</span> <span class="arrow down"></span></button> <button type="button" aria-label="编程分享" class="mobile-dropdown-title"><span class="title">编程分享</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="/编程分享/#入门必看-学习路线" class="nav-link">
  入门必看-学习路线
</a></li><li class="dropdown-item"><!----> <a href="/编程分享/#学习指南" class="nav-link">
  学习指南
</a></li><li class="dropdown-item"><!----> <a href="/编程分享/#开发经验" class="nav-link">
  开发经验
</a></li><li class="dropdown-item"><!----> <a href="/编程分享/#求职经验" class="nav-link">
  求职经验
</a></li><li class="dropdown-item"><!----> <a href="/编程分享/#职场经验" class="nav-link">
  职场经验
</a></li><li class="dropdown-item"><!----> <a href="/编程分享/#技术分享" class="nav-link">
  技术分享
</a></li><li class="dropdown-item"><!----> <a href="/编程分享/#实战教程" class="nav-link">
  实战教程
</a></li><li class="dropdown-item"><!----> <a href="/编程分享/#其他" class="nav-link">
  其他
</a></li><li class="dropdown-item"><!----> <a href="/编程分享/#📚-项目教程" class="nav-link">
  项目教程
</a></li><li class="dropdown-item"><!----> <a href="/编程分享/#个人作品" class="nav-link">
  个人作品
</a></li><li class="dropdown-item"><!----> <a href="/编程分享/#🎁-编程资源" class="nav-link">
  编程资源
</a></li><li class="dropdown-item"><!----> <a href="/编程分享/#🌐-科技科普" class="nav-link">
  科技科普
</a></li></ul></div></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="项目实战" class="dropdown-title"><span class="title">项目实战</span> <span class="arrow down"></span></button> <button type="button" aria-label="项目实战" class="mobile-dropdown-title"><span class="title">项目实战</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="/项目实战/OJ 判题系统.html" class="nav-link">
  OJ 判题系统
</a></li><li class="dropdown-item"><!----> <a href="/项目实战/智能 BI 平台.html" class="nav-link">
  智能 BI 平台
</a></li><li class="dropdown-item"><!----> <a href="/项目实战/聚合搜索平台.html" class="nav-link">
  聚合搜索平台
</a></li><li class="dropdown-item"><!----> <a href="/项目实战/API 开放平台.html" class="nav-link">
  API 开放平台
</a></li><li class="dropdown-item"><!----> <a href="/项目实战/伙伴匹配系统.html" class="nav-link">
  伙伴匹配系统
</a></li><li class="dropdown-item"><!----> <a href="/项目实战/用户中心项目.html" class="nav-link">
  用户中心项目
</a></li><li class="dropdown-item"><!----> <a href="/项目实战/Java 后端万用项目模板.html" class="nav-link">
  Java 后端万用项目模板
</a></li></ul></div></div><div class="nav-item"><a href="/知识碎片/" class="nav-link">
  知识碎片
</a></div><div class="nav-item"><a href="/编程导航/" class="nav-link">
  🔥 编程导航
</a></div><div class="nav-item"><a href="/产品服务/" class="nav-link">
  产品服务
</a></div><div class="nav-item"><a href="/作者/" class="nav-link">
  作者
</a></div> <a href="https://github.com/liyupi/codefather" target="_blank" rel="noopener noreferrer" class="repo-link">
    GitHub
    <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></nav>  <ul class="sidebar-links"><li><a href="/%E7%BC%96%E7%A8%8B%E5%88%86%E4%BA%AB/" class="sidebar-link">入门必看 - 学习路线</a></li><li><section class="sidebar-group collapsable depth-0"><p class="sidebar-heading"><span>入门必看-学习路线</span> <span class="arrow right"></span></p> <!----></section></li><li><section class="sidebar-group collapsable depth-0"><p class="sidebar-heading"><span>学习指南</span> <span class="arrow right"></span></p> <!----></section></li><li><section class="sidebar-group collapsable depth-0"><p class="sidebar-heading"><span>开发经验</span> <span class="arrow right"></span></p> <!----></section></li><li><section class="sidebar-group collapsable depth-0"><p class="sidebar-heading"><span>求职经验</span> <span class="arrow right"></span></p> <!----></section></li><li><section class="sidebar-group collapsable depth-0"><p class="sidebar-heading"><span>职场经验</span> <span class="arrow right"></span></p> <!----></section></li><li><section class="sidebar-group collapsable depth-0"><p class="sidebar-heading"><span>技术分享</span> <span class="arrow right"></span></p> <!----></section></li><li><section class="sidebar-group collapsable depth-0"><p class="sidebar-heading"><span>实战教程</span> <span class="arrow right"></span></p> <!----></section></li><li><section class="sidebar-group collapsable depth-0"><p class="sidebar-heading"><span>项目教程</span> <span class="arrow right"></span></p> <!----></section></li><li><section class="sidebar-group collapsable depth-0"><p class="sidebar-heading"><span>编程资源</span> <span class="arrow right"></span></p> <!----></section></li><li><section class="sidebar-group collapsable depth-0"><p class="sidebar-heading"><span>科技科普</span> <span class="arrow right"></span></p> <!----></section></li><li><section class="sidebar-group collapsable depth-0"><p class="sidebar-heading"><span>其他</span> <span class="arrow right"></span></p> <!----></section></li></ul> </aside> <main class="page"> <div class="content"><div style="width:100%"><div class="theme-default-content custom-content content__default"><h1 id="快速部署微服务项目-保姆级教程"><a href="#快速部署微服务项目-保姆级教程" class="header-anchor">#</a> 快速部署微服务项目，保姆级教程</h1> <blockquote><p>本文作者：<a href="https://yuyuanweb.feishu.cn/wiki/Abldw5WkjidySxkKxU2cQdAtnah" target="_blank" rel="noopener noreferrer">程序员鱼皮<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></p> <p>本站地址：<a href="https://codefather.cn" target="_blank" rel="noopener noreferrer">https://codefather.cn<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></p></blockquote> <p>大家好，我是鱼皮。</p> <p>项目上线是每位学编程同学必须掌握的基本技能。之前我已经给大家分享过很多种上线单体项目的方法了，今天再出一期微服务项目的部署教程，用一种最简单的方法，带大家轻松部署微服务项目。</p> <p>开始之前，先做个小调研啊，大家更喜欢看 “真实踩坑版” 的教程还是 “压缩纯净版” 的教程呢？</p> <p>本期教程我还是保持自己一贯的风格，依然是保姆级教程，包含了一些踩坑过程和解决方案，大家跟着做就完事儿~</p> <blockquote><p>更推荐看视频版：https://www.bilibili.com/video/BV1Cp4y1F7eA/</p></blockquote> <h2 id="项目介绍"><a href="#项目介绍" class="header-anchor">#</a> 项目介绍</h2> <p>这次的教程以我带大家全程直播手把手开发的、基于 Spring Cloud + Docker 代码沙箱的 <a href="http://mp.weixin.qq.com/s?__biz=MzI1NDczNTAwMA==&amp;mid=2247549858&amp;idx=1&amp;sn=dee63c9111558c81b8ee8921f871ea6f&amp;chksm=e9c2e455deb56d43d79e01c5ff310487fb66e16baef27f664e43a0e8779abd6506194fc216aa&amp;scene=21#wechat_redirect" target="_blank" rel="noopener noreferrer">在线判题系统<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a> 为例，进行演示。</p> <p>这个项目的核心功能是让用户能够在线选题和做题，然后由系统自动判题：</p> <p><img alt="" data-src="https://pic.yupi.icu/5563/202311071928283.png" loading="lazy" class="lazy"></p> <p>项目用到的核心依赖包括：MySQL 数据库、Redis 缓存、RabbitMQ 消息队列、Nacos 注册中心</p> <p>涉及的核心服务包括：用户服务、题目服务、判题服务（代码沙箱）、Gateway 网关服务</p> <p><img alt="" data-src="https://pic.yupi.icu/5563/202311071928469.png" loading="lazy" class="lazy"></p> <h2 id="传统部署"><a href="#传统部署" class="header-anchor">#</a> 传统部署</h2> <p>对于这样一个项目，如果我们还用传统单机项目的部署方式，一个个打 jar 包、用 Java 命令来启动，会有哪些问题呢？</p> <ol><li>要一个个安装依赖，比如 MySQL 数据库、Redis、消息队列、Nacos，非常麻烦！</li> <li>要一个个打 jar 包、一个个手动运行 jar 包，非常麻烦！</li> <li>不方便集中观察所有服务的运行状态和资源占用情况</li></ol> <p>所以，为了解决这些问题，我们会选用一种更高效的微服务部署方式 —— Docker Compose。</p> <h2 id="docker-compose-介绍"><a href="#docker-compose-介绍" class="header-anchor">#</a> Docker Compose 介绍</h2> <p>在介绍 Docker Compose 前，先简单介绍下 Docker。</p> <p>Docker 是一种容器技术，允许开发者将应用程序和所有依赖项（如代码、库、配置等）制作为 <code>镜像</code>。可以把镜像简单理解为软件安装包，可以在不同的计算机上通过它快速安装和启动应用程序（容器），这些程序独立隔离地运行，不受外部环境的影响。</p> <p><img alt="" data-src="https://pic.yupi.icu/5563/202311071928039.png" loading="lazy" class="lazy"></p> <p>如果要部署微服务项目，可能要启动多个 Docker 容器，比如 MySQL 容器、用户服务容器等。这时就需要 Docker Compose 了。它是一个容器编排助手，用于集中管理多个 Docker 容器的启动和协同工作。可以在一个配置文件中集中定义所有容器以及它们的关系。然后，可以使用一行命令启动所有容器，而不需要手动运行多个命令。</p> <p><img alt="" data-src="https://pic.yupi.icu/5563/202311071928296.png" loading="lazy" class="lazy"></p> <p>需要注意的是，Docker Compose 通常适用于把所有微服务部署在同一台服务器的场景，在真实的企业级项目中，往往会使用 K8S 等更专业的容器编排和自动化部署工具，更方便地在多个服务器上部署容器。</p> <h2 id="部署流程"><a href="#部署流程" class="header-anchor">#</a> 部署流程</h2> <p>了解了 Docker 和 Docker Compose 的作用后，我们来快速了解下部署流程，分为 2 大阶段 —— 本地部署和服务器部署。</p> <p>一、本地部署</p> <ol><li>梳理服务部署表格</li> <li>Maven 子父模块打包</li> <li>Dockerfile 编写</li> <li>编写环境依赖配置</li> <li>编写服务配置</li> <li>调整程序配置</li> <li>测试访问</li></ol> <p>二、服务端部署</p> <ol><li>准备服务器</li> <li>Docker Compose 安装</li> <li>同步文件</li> <li>获取 jar 包</li> <li>服务启动</li> <li>测试访问</li></ol> <h2 id="一、本地部署"><a href="#一、本地部署" class="header-anchor">#</a> 一、本地部署</h2> <p>第一阶段是本地部署，也可以叫做部署准备。</p> <p>强烈建议大家，比起直接操作线上服务器，最好是先在本地把所有的流程跑通，风险更低、效率更高。</p> <p>这里我使用的是 Mac 操作系统，已经安装了 Docker Desktop 软件，管理 Docker 容器会更方便一些。</p> <p><img alt="" data-src="https://pic.yupi.icu/5563/202311071928427.png" loading="lazy" class="lazy"></p> <p>对于本地没有 Docker 环境的同学，这一阶段仔细看一遍有个印象就足够了。可以直接拿我调试好的配置文件在服务器上部署，而不用自己调试。</p> <p>怎么样，够贴心吧！可以叫我 “保姆鱼皮”，简称 “保姆皮”。</p> <p><img alt="" data-src="https://pic.yupi.icu/5563/202311071928290.png" loading="lazy" class="lazy"></p> <h3 id="_1-1、梳理服务部署表格"><a href="#_1-1、梳理服务部署表格" class="header-anchor">#</a> 1.1、梳理服务部署表格</h3> <p>在部署微服务项目前，首先要规划好要部署哪些服务、以及各服务的关键信息，比如服务名称、版本号、占用端口号、关键配置等。</p> <p>对于我的在线判题项目，梳理好的服务表格如下：</p> <table><thead><tr><th style="text-align:left;">服务名称</th> <th style="text-align:left;">英文名</th> <th style="text-align:left;">端口号</th> <th style="text-align:left;">版本号</th> <th style="text-align:left;">服务类别</th></tr></thead> <tbody><tr><td style="text-align:left;">数据库</td> <td style="text-align:left;">mysql</td> <td style="text-align:left;">3306</td> <td style="text-align:left;">v8</td> <td style="text-align:left;">环境依赖</td></tr> <tr><td style="text-align:left;">缓存</td> <td style="text-align:left;">redis</td> <td style="text-align:left;">6379</td> <td style="text-align:left;">v6</td> <td style="text-align:left;">环境依赖</td></tr> <tr><td style="text-align:left;">消息队列</td> <td style="text-align:left;">rabbitmq</td> <td style="text-align:left;">5672, 15672</td> <td style="text-align:left;">v3.12.6</td> <td style="text-align:left;">环境依赖</td></tr> <tr><td style="text-align:left;">注册中心</td> <td style="text-align:left;">nacos</td> <td style="text-align:left;">8848</td> <td style="text-align:left;">v2.2.0</td> <td style="text-align:left;">环境依赖</td></tr> <tr><td style="text-align:left;">网关服务</td> <td style="text-align:left;">gateway</td> <td style="text-align:left;">8101</td> <td style="text-align:left;">java 8</td> <td style="text-align:left;">业务服务</td></tr> <tr><td style="text-align:left;">用户服务</td> <td style="text-align:left;">yuoj-backend-user-service</td> <td style="text-align:left;">8102</td> <td style="text-align:left;">java 8</td> <td style="text-align:left;">业务服务</td></tr> <tr><td style="text-align:left;">题目服务</td> <td style="text-align:left;">yuoj-backend-question-service</td> <td style="text-align:left;">8103</td> <td style="text-align:left;">java 8</td> <td style="text-align:left;">业务服务</td></tr> <tr><td style="text-align:left;">判题服务</td> <td style="text-align:left;">yuoj-backend-judge-service</td> <td style="text-align:left;">8104</td> <td style="text-align:left;">java 8</td> <td style="text-align:left;">业务服务</td></tr></tbody></table> <p>为什么这里我要划分服务类别为 “环境依赖” 和 “业务服务” 呢？</p> <p>因为在启动服务时，必须要先启动环境依赖，才能启动业务服务，否则就会报类似 “无法连接数据库” 之类的错误。</p> <h3 id="_1-2、maven-子父模块打包"><a href="#_1-2、maven-子父模块打包" class="header-anchor">#</a> 1.2、Maven 子父模块打包</h3> <p>对于微服务项目，我们通常是使用 Maven 的子父模块功能进行管理的。需要部署项目时，不用针对每个子服务单独执行 <code>mvn package</code> 命令进行打包，而是可以一键打包所有服务。</p> <p>想要实现这个功能，需要给子父模块的依赖文件（pom.xml）进行一些配置，主要包括：</p> <h4 id="_1-父模块配置"><a href="#_1-父模块配置" class="header-anchor">#</a> 1）父模块配置</h4> <p>在父模块的 pom.xml 文件中引入 <code>spring-boot-maven-plugin</code> 即可，注意一定不要配置 configuration 和 repackage！</p> <p>示例代码如下：</p> <div class="language- line-numbers-mode"><pre class="language-text"><code>&lt;plugin&gt;
    &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
    &lt;artifactId&gt;spring-boot-maven-plugin&lt;/artifactId&gt;
    &lt;version&gt;${spring-boot.version}&lt;/version&gt;
&lt;/plugin&gt;
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br></div></div><h4 id="_2-子模块配置"><a href="#_2-子模块配置" class="header-anchor">#</a> 2）子模块配置</h4> <p>修改所有需要启动 Spring Boot 的服务（用户服务、题目服务、判题服务、网关服务）的子模块 pom.xml 文件。</p> <p>主要是增加 executions 配置，使用 spring-boot-maven-plugin 的 repackage 命令来构建子模块，从而自动在构建时将公共模块的依赖打入 jar 包。</p> <p>示例代码如下：</p> <div class="language- line-numbers-mode"><pre class="language-text"><code>&lt;plugin&gt;
    &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
    &lt;artifactId&gt;spring-boot-maven-plugin&lt;/artifactId&gt;
    &lt;executions&gt;
        &lt;execution&gt;
            &lt;id&gt;repackage&lt;/id&gt;
            &lt;goals&gt;
                &lt;goal&gt;repackage&lt;/goal&gt;
            &lt;/goals&gt;
        &lt;/execution&gt;
    &lt;/executions&gt;
&lt;/plugin&gt;
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br></div></div><h3 id="_1-3、dockerfile-编写"><a href="#_1-3、dockerfile-编写" class="header-anchor">#</a> 1.3、Dockerfile 编写</h3> <p>Dockerfile 是定义 Docker 容器镜像构建过程的文件，包括容器镜像使用的基础环境、容器内的依赖和文件、容器的配置、启动命令等。</p> <p>有了 Dockerfile，我们就能很轻松地制作出自己的容器镜像。</p> <p>虽然 Dockerfile 的写法并不复杂，但我还是建议大家尽量不要自己写，直接去网上找个差不多的项目，复制粘贴别人的 Dockerfile 就足够了！</p> <p>这里鱼皮给大家提供 2 种常用的 Spring Boot 项目的 Dockerfile。</p> <h4 id="_1-复制-jar-包版"><a href="#_1-复制-jar-包版" class="header-anchor">#</a> 1）复制 jar 包版</h4> <p>思路：在本地打好 jar 包后，复制 jar 包到容器中运行</p> <p>示例代码如下：</p> <div class="language- line-numbers-mode"><pre class="language-text"><code># 基础镜像
FROM openjdk:8-jdk-alpine

# 指定工作目录
WORKDIR /app

# 将 jar 包添加到工作目录，比如 target/yuoj-backend-user-service-0.0.1-SNAPSHOT.jar
ADD {本地 jar 包路径} . 

# 暴露端口
EXPOSE {服务端口号}

# 启动命令
ENTRYPOINT [&quot;java&quot;,&quot;-jar&quot;,&quot;/app/{jar 包名称}&quot;,&quot;--spring.profiles.active=prod&quot;]
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br></div></div><h4 id="_2-maven-打包版"><a href="#_2-maven-打包版" class="header-anchor">#</a> 2）Maven 打包版</h4> <p>思路：复制本地代码到容器中，在容器中使用 Maven 打包再运行</p> <p>示例代码如下：</p> <div class="language- line-numbers-mode"><pre class="language-text"><code># 基础镜像
FROM maven:3.8.1-jdk-8-slim as builder

# 指定工作目录
WORKDIR /app

# 添加源码文件
COPY pom.xml .
COPY src ./src

# 构建 jar 包，跳过测试
RUN mvn package -DskipTests

# 启动命令
ENTRYPOINT [&quot;java&quot;,&quot;-jar&quot;,&quot;/app/target/{jar 包名称}&quot;,&quot;--spring.profiles.active=prod&quot;]
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br></div></div><p>此处由于我们的微服务项目可以一键打好所有子服务的 jar 包，就没必要每个服务单独在容器中打包了，所以选择第一种方式的 Dockerfile。</p> <p>我们需要给每个 Spring Boot 服务（用户服务、题目服务、判题服务、网关服务）都编写一个 Dockerfile，放到每个子服务的根目录下。</p> <p><img alt="" data-src="https://pic.yupi.icu/5563/202311071928486.png" loading="lazy" class="lazy"></p> <p>以用户服务为例，示例代码如下：</p> <div class="language- line-numbers-mode"><pre class="language-text"><code># 基础镜像
FROM openjdk:8-jdk-alpine
  
# 指定工作目录
WORKDIR /app
  
# 将 jar 包添加到工作目录，比如 target/yuoj-backend-user-service-0.0.1-SNAPSHOT.jar
ADD target/yuoj-backend-user-service-0.0.1-SNAPSHOT.jar .
  
# 暴露端口
EXPOSE 8102
  
# 启动命令
ENTRYPOINT [&quot;java&quot;,&quot;-jar&quot;,&quot;/app/yuoj-backend-user-service-0.0.1-SNAPSHOT.jar&quot;,&quot;--spring.profiles.active=prod&quot;]
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br></div></div><p>建议先在本地利用 IDEA 开发工具调通镜像构建流程，确保每个 Dockerfile 都是可以成功制作镜像的：</p> <p><img alt="" data-src="https://pic.yupi.icu/5563/202311071928506.png" loading="lazy" class="lazy"></p> <p>查看容器的启动日志，发现能够启动服务、看到 Spring 图标即可：</p> <p><img alt="" data-src="https://pic.yupi.icu/5563/202311071928160.png" loading="lazy" class="lazy"></p> <h3 id="_1-4、编写环境依赖配置"><a href="#_1-4、编写环境依赖配置" class="header-anchor">#</a> 1.4、编写环境依赖配置</h3> <p>接下来，我们就要编写 Docker Compose 的配置文件了，可以根据配置文件快速启动多个服务。</p> <p>之前我们已经梳理了服务部署表格，将服务划分为了 “环境依赖” 和 “业务服务”。</p> <p>由于业务服务依赖 MySQL 等环境依赖，所以需要拆分 2 套 Docker Compose 的配置文件，分别为 <code>docker-compose.env.yml</code> 环境配置和 <code>docker-compose.service.yml</code> 业务服务配置，保证先成功启动依赖，再启动服务。</p> <p>学过 Docker Compose 的同学可能听说过 depends_on 配置，也能决定服务的启动顺序。但是千万注意，depends_on 并不会等待服务完全就绪，只是确保它们在启动时的顺序，并不稳定。</p> <p>如何编写 Docker Compose 文件呢？</p> <p>和 Dockerfile 一样，直接去网上找现成的 Docker Compose file，复制粘贴过来略做修改就能使用了~</p> <p>再配合以下 2 个网站，完全无需记忆 Docker Compose 的写法！</p> <ul><li>Docker Compose file 官方文档：https://docs.docker.com/compose/compose-file/</li> <li>搜索现成的 Docker 镜像：https://hub.docker.com/</li></ul> <p>当然，现在 AI 时代了，还有更简单的方式！</p> <p>直接把我们整理好的服务部署需要喂给 GPT，让 AI 帮我们生成配置即可~</p> <p>示例 prompt：</p> <div class="language- line-numbers-mode"><pre class="language-text"><code>现在我需要用 docker compose 来部署 mysql 8（3306 端口）username=root,password=123456
redis 6（无密码，6379端口）、rabbitmq v.3.12.6（ 5672 端口   password: guest，username: guest）、nacos 2.2.0（8848端口）；还有 4 个本地的 springboot 服务（名称分别为：yuoj-backend-user-service 8102端口、yuoj-backend-question-service 8103端口、yuoj-backend-judge-service 8104端口、yuoj-backend-gateway 8101 端口），每个服务本地目录都有一个 Dockerfile，请帮我自动生成 docker compose 的 yml 配置文件，要求这些服务网络能够连通
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br></div></div><p>效果还是非常不错的，只要你描述地足够清楚，生成的配置完全可用！</p> <p><img alt="" data-src="https://pic.yupi.icu/5563/202311071928734.png" loading="lazy" class="lazy"></p> <p>由于这篇文章是教程嘛，我就带大家通过调试的方式一步步完成 Docker Compose 文件，最后会把完整的 Docker Compose 文件给大家分享出来，大家直接用就行了~</p> <p>我们要分别在 Docker Compose 中定义 4 大基础依赖，包括 MySQL、Redis、RabbitMQ 和 Nacos。</p> <h4 id="_1-mysql"><a href="#_1-mysql" class="header-anchor">#</a> 1）MySQL</h4> <p>我们不仅要创建一个 MySQL 服务，还要在创建服务后自动创建我们需要的库表结构。</p> <p>所以需要先准备数据库 SQL 脚本文件，里面包含了建库、建表语句，我们把它放在微服务项目根目录的 <code>mysql-init</code> 文件夹中：</p> <p>鱼皮带大家做的每个项目都提供了现成的建表语句，这是一个非常好的开发习惯，便于其他人快速启动你的项目。</p> <p><img alt="" data-src="https://pic.yupi.icu/5563/202311071928971.png" loading="lazy" class="lazy"></p> <p>由于要在本地启动 MySQL，还需要定义一个文件夹 <code>.mysql-data</code> 来存放 MySQL 的持久化数据，防止容器重启后数据丢失。</p> <p>做好这两点后，就可以编写 <code>docker-compose.env.yml</code> 文件了，先只写一个 MySQL 服务，示例代码如下：</p> <p>关键配置的含义我都写到注释里了</p> <div class="language- line-numbers-mode"><pre class="language-text"><code>version: '3'
services:
  mysql:
    image: mysql:8 # 使用的镜像
    container_name: yuoj-mysql # 启动的实例名称
    environment:
      MYSQL_ROOT_PASSWORD: 123456 # root 用户密码
    ports:
      - &quot;3306:3306&quot; # 端口映射
    volumes:
      - ./.mysql-data:/var/lib/mysql # 将数据目录挂载到本地目录以进行持久化
      - ./mysql-init:/docker-entrypoint-initdb.d # 自动执行启动脚本
    restart: always # 崩溃后自动重启
    networks:
      - mynetwork # 指定网络
networks:
  mynetwork: # 自定义网络，实现网络互通和隔离
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br></div></div><p>写好配置文件后，可以直接在 IDEA 里执行 Docker Compose 文件，调试 MySQL 的运行：</p> <p><img alt="" data-src="https://pic.yupi.icu/5563/202311071928011.png" loading="lazy" class="lazy"></p> <p>运行成功后，我们可以在本地成功连接数据库：</p> <p><img alt="" data-src="https://mmbiz.qpic.cn/mmbiz_png/mngWTkJEOYKWGoz54KwujA7s17P0ZCyew5moibS6Oc1NK9Vw7bPbgrbsZBicEQiaDPrGV5GP3L3dGdictrz0cnZkDA/640?wx_fmt=png&amp;wxfrom=5&amp;wx_lazy=1&amp;wx_co=1" loading="lazy" class="lazy"></p> <h4 id="_2-redis"><a href="#_2-redis" class="header-anchor">#</a> 2）Redis</h4> <p>Redis 服务的定义和启动操作和 MySQL 服务几乎一致，Redis 的 Docker Compose 配置示例代码如下：</p> <div class="language- line-numbers-mode"><pre class="language-text"><code>version: '3'
services:
  redis:
    image: redis:6
    container_name: yuoj-redis
    ports:
      - &quot;6379:6379&quot;
    networks:
      - mynetwork
    volumes:
      - ./.redis-data:/data # 持久化
networks:
  mynetwork:
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br></div></div><p>然后在本地执行 Docker Compose 文件，启动 Redis 服务，并且尝试进入 Terminal 来调试 Redis：</p> <p><img alt="" data-src="https://mmbiz.qpic.cn/mmbiz_png/mngWTkJEOYKWGoz54KwujA7s17P0ZCye45cNbBJT9oV9qqqFFlGQJIu7tVgVZe2YEhibOMC7C7wIDkXNMzZU3yg/640?wx_fmt=png&amp;wxfrom=5&amp;wx_lazy=1&amp;wx_co=1" loading="lazy" class="lazy"></p> <h4 id="_3-rabbitmq"><a href="#_3-rabbitmq" class="header-anchor">#</a> 3）RabbitMQ</h4> <p>同 MySQL 和 Redis，RabbitMQ 的 Docker Compose 配置示例代码如下：</p> <div class="language- line-numbers-mode"><pre class="language-text"><code>version: '3'
services:
  rabbitmq:
    image: rabbitmq:3.12.6-management # 支持管理面板的消息队列
    container_name: yuoj-rabbitmq
    environment:
      RABBITMQ_DEFAULT_USER: guest
      RABBITMQ_DEFAULT_PASS: guest
    ports:
      - &quot;5672:5672&quot;
      - &quot;15672:15672&quot; # RabbitMQ Dashboard 端口
    volumes:
      - ./.rabbitmq-data:/var/lib/rabbitmq # 持久化
    networks:
      - mynetwork
networks:
  mynetwork:
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br></div></div><p>本地执行 Docker Compose 文件，启动 RabbitMQ 服务，然后可以访问 <code>localhost:15672</code> 查看到管理面板，就表示启动成功了~</p> <p>账号密码都是 guest</p> <p><img alt="" data-src="https://mmbiz.qpic.cn/mmbiz_png/mngWTkJEOYKWGoz54KwujA7s17P0ZCyehG7bfEHLT6UBiaVJZYKicuib92TB0REnpBkQGyCyMe1W80amqQxiaiczlzw/640?wx_fmt=png&amp;wxfrom=5&amp;wx_lazy=1&amp;wx_co=1" loading="lazy" class="lazy"></p> <h4 id="_4-nacos"><a href="#_4-nacos" class="header-anchor">#</a> 4）Nacos</h4> <p>和其他服务一样，Nacos 也需要编写 Docker Compose 配置。</p> <p>但是在选择 Nacos 镜像时必须要注意，建议选择支持 linux/arm64 架构的镜像版本，比如 <code>v2.2.0-slim</code>，否则后面可能会无法运行：</p> <p><img alt="" data-src="https://pic.yupi.icu/5563/202311071928872.png" loading="lazy" class="lazy"></p> <p>Nacos 示例配置文件如下：</p> <div class="language- line-numbers-mode"><pre class="language-text"><code>version: '3'
services:
  nacos:
    image: nacos/nacos-server:v2.2.0-slim
    container_name: yuoj-nacos
    ports:
      - &quot;8848:8848&quot;
    volumes:
      - ./.nacos-data:/home/nacos/data
    networks:
      - mynetwork
    environment:
      - MODE=standalone # 单节点模式启动
      - PREFER_HOST_MODE=hostname # 支持 hostname
      - TZ=Asia/Shanghai # 控制时区
networks:
  mynetwork:
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br></div></div><p>然后在本地执行 Docker Compose 启动 Nacos，访问 <code>localhost:8848/nacos</code> 能够看到管理页面，就表示运行成功了~</p> <p>管理页面的账号和密码默认都是 nacos</p> <p><img alt="" data-src="https://mmbiz.qpic.cn/mmbiz_png/mngWTkJEOYKWGoz54KwujA7s17P0ZCyeo34e4ic4JAzA1fZ2GPgibIQlkWFe7Q3FrmwstcmLOIMdda0Yb6OzgEcA/640?wx_fmt=png&amp;wxfrom=5&amp;wx_lazy=1&amp;wx_co=1" loading="lazy" class="lazy"></p> <h4 id="完整-docker-compose-文件"><a href="#完整-docker-compose-文件" class="header-anchor">#</a> 完整 Docker Compose 文件</h4> <p>分别调试完上述服务后，我们把所有的配置拼在一起，就得到了完整的文件，文件名为 <code>docker-compose.env.yml</code>。</p> <p>完整代码如下：</p> <div class="language- line-numbers-mode"><pre class="language-text"><code>version: '3'
services:
  mysql:
    image: mysql:8 # 使用的镜像
    container_name: yuoj-mysql # 启动的实例名称
    environment:
      MYSQL_ROOT_PASSWORD: 123456 # root 用户密码
    ports:
      - &quot;3306:3306&quot; # 端口映射
    volumes:
      - ./.mysql-data:/var/lib/mysql # 将数据目录挂载到本地目录以进行持久化
      - ./mysql-init:/docker-entrypoint-initdb.d # 启动脚本
    restart: always # 崩溃后自动重启
    networks:
      - mynetwork # 指定网络
  redis:
    image: redis:6
    container_name: yuoj-redis
    ports:
      - &quot;6379:6379&quot;
    networks:
      - mynetwork
    volumes:
      - ./.redis-data:/data # 持久化
  rabbitmq:
    image: rabbitmq:3.12.6-management # 支持管理面板的消息队列
    container_name: yuoj-rabbitmq
    environment:
      RABBITMQ_DEFAULT_USER: guest
      RABBITMQ_DEFAULT_PASS: guest
    ports:
      - &quot;5672:5672&quot;
      - &quot;15672:15672&quot; # RabbitMQ Dashboard 端口
    volumes:
      - ./.rabbitmq-data:/var/lib/rabbitmq # 持久化
    networks:
      - mynetwork
  nacos:
    image: nacos/nacos-server:v2.2.0-slim
    container_name: yuoj-nacos
    ports:
      - &quot;8848:8848&quot;
    volumes:
      - ./.nacos-data:/home/nacos/data
    networks:
      - mynetwork
    environment:
      - MODE=standalone # 单节点模式启动
      - PREFER_HOST_MODE=hostname # 支持 hostname
      - TZ=Asia/Shanghai # 控制时区
networks:
  mynetwork:
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br><span class="line-number">19</span><br><span class="line-number">20</span><br><span class="line-number">21</span><br><span class="line-number">22</span><br><span class="line-number">23</span><br><span class="line-number">24</span><br><span class="line-number">25</span><br><span class="line-number">26</span><br><span class="line-number">27</span><br><span class="line-number">28</span><br><span class="line-number">29</span><br><span class="line-number">30</span><br><span class="line-number">31</span><br><span class="line-number">32</span><br><span class="line-number">33</span><br><span class="line-number">34</span><br><span class="line-number">35</span><br><span class="line-number">36</span><br><span class="line-number">37</span><br><span class="line-number">38</span><br><span class="line-number">39</span><br><span class="line-number">40</span><br><span class="line-number">41</span><br><span class="line-number">42</span><br><span class="line-number">43</span><br><span class="line-number">44</span><br><span class="line-number">45</span><br><span class="line-number">46</span><br><span class="line-number">47</span><br><span class="line-number">48</span><br><span class="line-number">49</span><br><span class="line-number">50</span><br><span class="line-number">51</span><br><span class="line-number">52</span><br></div></div><h3 id="_1-5、编写业务服务配置"><a href="#_1-5、编写业务服务配置" class="header-anchor">#</a> 1.5、编写业务服务配置</h3> <p>用同样的方式，我们可以编写业务服务的 Docker Compose 文件，文件名称 <code>docker-compose.service.yml</code>。</p> <p>示例代码如下，其中需要格外关注的配置是 build 和 depends_on：</p> <div class="language- line-numbers-mode"><pre class="language-text"><code>version: '3'
services:
  yuoj-backend-gateway:
    container_name: yuoj-backend-gateway
    build: # 服务的 Docker 构建文件位置
      context: ./yuoj-backend-gateway
      dockerfile: Dockerfile
    ports:
      - &quot;8101:8101&quot;
    networks:
      - mynetwork
  
  yuoj-backend-user-service:
    container_name: yuoj-backend-user-service
    build:
      context: ./yuoj-backend-user-service
      dockerfile: Dockerfile
    ports:
      - &quot;8102:8102&quot;
    networks:
      - mynetwork
    depends_on: # 本服务依赖的服务，控制启动先后顺序
      - yuoj-backend-gateway

  yuoj-backend-question-service:
    container_name: yuoj-backend-question-service
    build:
      context: ./yuoj-backend-question-service
      dockerfile: Dockerfile
    ports:
      - &quot;8103:8103&quot;
    networks:
      - mynetwork
    depends_on:
      - yuoj-backend-user-service
      - yuoj-backend-gateway

  yuoj-backend-judge-service:
    container_name: yuoj-backend-judge-service
    build:
      context: ./yuoj-backend-judge-service
      dockerfile: Dockerfile
    ports:
      - &quot;8104:8104&quot;
    networks:
      - mynetwork
    depends_on:
      - yuoj-backend-user-service
      - yuoj-backend-question-service
      - yuoj-backend-gateway

# 网络，不定义的话就是默认网络
networks:
  mynetwork:
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br><span class="line-number">19</span><br><span class="line-number">20</span><br><span class="line-number">21</span><br><span class="line-number">22</span><br><span class="line-number">23</span><br><span class="line-number">24</span><br><span class="line-number">25</span><br><span class="line-number">26</span><br><span class="line-number">27</span><br><span class="line-number">28</span><br><span class="line-number">29</span><br><span class="line-number">30</span><br><span class="line-number">31</span><br><span class="line-number">32</span><br><span class="line-number">33</span><br><span class="line-number">34</span><br><span class="line-number">35</span><br><span class="line-number">36</span><br><span class="line-number">37</span><br><span class="line-number">38</span><br><span class="line-number">39</span><br><span class="line-number">40</span><br><span class="line-number">41</span><br><span class="line-number">42</span><br><span class="line-number">43</span><br><span class="line-number">44</span><br><span class="line-number">45</span><br><span class="line-number">46</span><br><span class="line-number">47</span><br><span class="line-number">48</span><br><span class="line-number">49</span><br><span class="line-number">50</span><br><span class="line-number">51</span><br><span class="line-number">52</span><br><span class="line-number">53</span><br><span class="line-number">54</span><br></div></div><h3 id="_1-6、调整程序配置"><a href="#_1-6、调整程序配置" class="header-anchor">#</a> 1.6、调整程序配置</h3> <p>编写好上述配置文件后，本地尝试运行 Docker Compose 业务服务，结果发现：报错啦！依赖服务的地址访问不通！</p> <p>这是由于之前我们的项目访问依赖服务时，全部是使用了固定的 IP 地址（比如 localhost），而容器内部的 localhost（或 127.0.0.1）通常指向容器本身，而不是宿主主机。所以为了在容器内访问其他服务，程序中应该使用服务名称而不是 localhost。</p> <p>我们给每个 Spring Boot 服务都增加一套 prod 上线配置，在配置中更改服务调用地址。</p> <p>用户服务、题目服务和判题服务的 <code>application-prod.yml</code> 配置修改如下：</p> <div class="language- line-numbers-mode"><pre class="language-text"><code># 生产环境配置文件
spring:
  # 数据库配置
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://mysql:3306/yuoj # localhost 改为 mysql
    username: root
    password: 123456
  # Redis 配置
  redis:
    database: 1
    host: redis # localhost 改为 redis
    port: 6379
    timeout: 5000
  cloud:
    nacos:
      discovery:
        server-addr: nacos:8848 # localhost 改为 nacos
  rabbitmq:
    host: rabbitmq # localhost 改为 rabbitmq
    port: 5672
    password: guest
    username: guest
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br><span class="line-number">19</span><br><span class="line-number">20</span><br><span class="line-number">21</span><br><span class="line-number">22</span><br><span class="line-number">23</span><br></div></div><p>Gateway 网关服务的配置修改如下：</p> <div class="language- line-numbers-mode"><pre class="language-text"><code>spring:
  cloud:
    nacos:
      discovery:
        server-addr: nacos:8848 # localhost 改为 nacos
    gateway:
      routes:
        - id: yuoj-backend-user-service
          uri: lb://yuoj-backend-user-service
          predicates:
            - Path=/api/user/**
        - id: yuoj-backend-question-service
          uri: lb://yuoj-backend-question-service
          predicates:
            - Path=/api/question/**
        - id: yuoj-backend-judge-service
          uri: lb://yuoj-backend-judge-service
          predicates:
            - Path=/api/judge/**
  application:
    name: yuoj-backend-gateway
  main:
    web-application-type: reactive
server:
  port: 8101
knife4j:
  gateway:
    enabled: true
    strategy: discover
    discover:
      enabled: true
      version: swagger2
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br><span class="line-number">19</span><br><span class="line-number">20</span><br><span class="line-number">21</span><br><span class="line-number">22</span><br><span class="line-number">23</span><br><span class="line-number">24</span><br><span class="line-number">25</span><br><span class="line-number">26</span><br><span class="line-number">27</span><br><span class="line-number">28</span><br><span class="line-number">29</span><br><span class="line-number">30</span><br><span class="line-number">31</span><br><span class="line-number">32</span><br></div></div><p>然后执行 <code>mvn package</code> 命令重新打包、执行 Docker Compose。</p> <p>结果发现大多数服务都启动了，但是判题服务还有报错。</p> <p><img alt="" data-src="https://mmbiz.qpic.cn/mmbiz_png/mngWTkJEOYKWGoz54KwujA7s17P0ZCyeL0LEVCoInX5rCJFib6PvGcJrzn9XYUAyFBCI0hACtAo14NU1WtKOMKg/640?wx_fmt=png&amp;wxfrom=5&amp;wx_lazy=1&amp;wx_co=1" loading="lazy" class="lazy"></p> <p>这是因为程序在创建消息队列时存在硬编码的变量，指定了 host 为 &quot;localhost&quot;，示例代码如下：</p> <div class="language- line-numbers-mode"><pre class="language-text"><code>ConnectionFactory factory = new ConnectionFactory();
factory.setHost(&quot;localhost&quot;);
Connection connection = factory.newConnection();
Channel channel = connection.createChannel();
String EXCHANGE_NAME = &quot;code_exchange&quot;;
channel.exchangeDeclare(EXCHANGE_NAME, &quot;direct&quot;);
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br></div></div><p>举这个例子是为了告诉大家，在程序中尽量不要写固定 IP 或域名，全部改为动态读取配置文件，便于修改。</p> <p>示例修改后的代码如下：</p> <div class="language- line-numbers-mode"><pre class="language-text"><code>/**
 * 用于创建测试程序用到的交换机和队列（只用在程序启动前执行一次）
 */
@Slf4j
@Component
public class InitRabbitMqBean {

    @Value(&quot;${spring.rabbitmq.host:localhost}&quot;)
    private String host;

    @PostConstruct
    public void init() {
        try {
            ConnectionFactory factory = new ConnectionFactory();
            factory.setHost(host);
            Connection connection = factory.newConnection();
            Channel channel = connection.createChannel();
            String EXCHANGE_NAME = &quot;code_exchange&quot;;
            channel.exchangeDeclare(EXCHANGE_NAME, &quot;direct&quot;);

            // 创建队列，随机分配一个队列名称
            String queueName = &quot;code_queue&quot;;
            channel.queueDeclare(queueName, true, false, false, null);
            channel.queueBind(queueName, EXCHANGE_NAME, &quot;my_routingKey&quot;);
            log.info(&quot;消息队列启动成功&quot;);
        } catch (Exception e) {
            log.error(&quot;消息队列启动失败&quot;);
        }
    }
}
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br><span class="line-number">19</span><br><span class="line-number">20</span><br><span class="line-number">21</span><br><span class="line-number">22</span><br><span class="line-number">23</span><br><span class="line-number">24</span><br><span class="line-number">25</span><br><span class="line-number">26</span><br><span class="line-number">27</span><br><span class="line-number">28</span><br><span class="line-number">29</span><br><span class="line-number">30</span><br></div></div><h3 id="_1-7、测试访问"><a href="#_1-7、测试访问" class="header-anchor">#</a> 1.7、测试访问</h3> <p>修复上述问题后，所有服务都可以通过 Docker Compose 文件启动了。</p> <p>然后我们访问 <code>localhost:8101/doc.html</code> 网关地址，能够看到 Swagger 聚合接口文档。</p> <p><img alt="" data-src="https://pic.yupi.icu/5563/202311071928086.png" loading="lazy" class="lazy"></p> <p>依次调用用户注册 =&gt; 登录 =&gt; 获取登录用户信息 =&gt; 创建题目接口，全部执行成功。</p> <p>至此，第一阶段就完成啦。</p> <h2 id="二、服务器部署"><a href="#二、服务器部署" class="header-anchor">#</a> 二、服务器部署</h2> <p>在第二阶段，我们的目标就是在真实的 Linux 服务器上部署微服务项目。有了第一阶段的准备，第二阶段简直可以说是易如反掌！</p> <h3 id="_2-1、准备服务器"><a href="#_2-1、准备服务器" class="header-anchor">#</a> 2.1、准备服务器</h3> <p>首先，我们要有一台 Linux 服务器。</p> <p>选择服务器前，我们必须要评估下微服务项目的内存占用，千万别把服务器的内存买小了！</p> <p>可以使用 Docker Desktop 直接查看内存占用，虚拟机内存大概占用了 8 个 G、容器实际内存占用了 4 个 G：</p> <p><img alt="" data-src="https://pic.yupi.icu/5563/202311071928105.png" loading="lazy" class="lazy"></p> <p>那我们搞多少内存的服务器呢？</p> <p>我猜很多同学会说 8 G，奈何我天生反骨，明知山有虎偏向虎山行（主要是想省 💰），我就搞一台 2 核 4 G 的服务器吧（发行版是 CentOS 7.9 Linux），咱们来猜一猜它够不够部署这套有 4 个业务服务的微服务项目呢？</p> <p>咱们一起来见证下！</p> <h3 id="_2-2、docker-compose-安装"><a href="#_2-2、docker-compose-安装" class="header-anchor">#</a> 2.2、Docker Compose 安装</h3> <p>有了服务器后，直接参考 Docker Compose 官方文档来安装。这里我们使用 Docker Compose V2 版本，相比 V1 版本统一了命令，使用更方便：</p> <p>Docker Compose V2 地址：https://docs.docker.com/compose/migrate/</p> <p>Docker Compose Linux 安装：https://docs.docker.com/compose/install/linux/#install-using-the-repository</p> <p><img alt="" data-src="https://pic.yupi.icu/5563/202311071928154.png" loading="lazy" class="lazy"></p> <p>安装过程很简单，跟着官方文档来就行了，主要包括以下几个步骤：</p> <p>1）设定安装来源：</p> <div class="language- line-numbers-mode"><pre class="language-text"><code>sudo yum install -y yum-utils
sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br></div></div><p>2）安装 Docker 和 Docker Compose：</p> <div class="language- line-numbers-mode"><pre class="language-text"><code>sudo yum install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br></div></div><p>3）启动 Docker：</p> <div class="language- line-numbers-mode"><pre class="language-text"><code>sudo systemctl start docker
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br></div></div><p>4）测试 Docker：</p> <div class="language- line-numbers-mode"><pre class="language-text"><code>systemctl status docker
sudo docker run hello-world
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br></div></div><h3 id="_2-3、同步文件"><a href="#_2-3、同步文件" class="header-anchor">#</a> 2.3、同步文件</h3> <p>接下来，我们需要把本地折腾好的微服务项目源码上传到服务器上，可以选择用 FTP 或 SSH 连接文件手动上传文件。</p> <p>我这里使用 JetBrains 开发工具的远程部署功能，可以配置文件自动上传，步骤如下：</p> <p>1）进入远程部署配置</p> <p><img alt="" data-src="https://pic.yupi.icu/5563/202311071928220.png" loading="lazy" class="lazy"></p> <p>2）添加远程部署配置：</p> <p>这里建议大家不要暴露自己的服务器 IP 啊，当你看到本文的时候，其实我已经把服务器的 IP 更换掉了哈哈哈哈哈哈哈哈！</p> <p><img alt="" data-src="https://pic.yupi.icu/5563/202311071928130.png" loading="lazy" class="lazy"></p> <p>3）指定连接的服务器配置：</p> <p><img alt="" data-src="https://pic.yupi.icu/5563/202311071928000.png" loading="lazy" class="lazy"></p> <p>4）配置本地文件和服务器文件路径映射：</p> <p><img alt="" data-src="https://pic.yupi.icu/5563/202311071928314.png" loading="lazy" class="lazy"></p> <p>5）开启自动上传：</p> <p><img alt="" data-src="https://pic.yupi.icu/5563/202311071928688.png" loading="lazy" class="lazy"></p> <p>6）首次需要手动上传文件。</p> <p>上传前记得先删除无用的文件，然后右键项目根目录，点击部署上传代码：</p> <p><img alt="" data-src="https://pic.yupi.icu/5563/202311071928706.png" loading="lazy" class="lazy"></p> <p>上传成功，在服务器对应路径（/code/yuoj-backend-microservice）下能看到已上传的文件列表：</p> <p><img alt="" data-src="https://pic.yupi.icu/5563/202311071928727.png" loading="lazy" class="lazy"></p> <h3 id="_2-4、获取-jar-包"><a href="#_2-4、获取-jar-包" class="header-anchor">#</a> 2.4、获取 jar 包</h3> <p>光把代码上传到服务器还是不够的，因为我们构建 Docker 镜像需要 jar 包。</p> <p>有 2 种方式得到 jar 包：</p> <ol><li>本地执行 <code>mvn package</code> 打好 jar 包，然后再上传</li> <li>服务器上装 Maven，在服务器上打包</li></ol> <p>但是因为 jar 包比较大，频繁改动的话同步速度会比较慢，所以更建议第二种方式，步骤如下：</p> <p>1）安装 Maven：</p> <div class="language- line-numbers-mode"><pre class="language-text"><code>sudo yum install maven
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br></div></div><p>2）安装好后，执行打包：</p> <div class="language- line-numbers-mode"><pre class="language-text"><code>sudo mvn package
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br></div></div><p>打包成功：</p> <p><img alt="" data-src="https://pic.yupi.icu/5563/202311071928733.png" loading="lazy" class="lazy"></p> <h3 id="_2-5、服务启动"><a href="#_2-5、服务启动" class="header-anchor">#</a> 2.5、服务启动</h3> <p>所有一切准备就绪，接下来就是使用 Docker Compose 命令分别启动环境依赖和业务服务啦。</p> <h4 id="_1-启动环境依赖"><a href="#_1-启动环境依赖" class="header-anchor">#</a> 1）启动环境依赖</h4> <p>先使用 docker compose 一行命令启动环境依赖：</p> <div class="language- line-numbers-mode"><pre class="language-text"><code>docker compose -f docker-compose.env.yml up
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br></div></div><p>注意：</p> <ol><li>老版本使用 &quot;docker-compose&quot; 替代 &quot;docker compose&quot;</li> <li>如果没有权限，命令前加上 &quot;sudo&quot;</li></ol> <p>然后喝杯咖啡，等待启动即可~</p> <p>启动成功后，我们可以通过公网 IP 来尝试访问服务。</p> <p>先进入到云服务商的服务器配置页，修改服务器的防火墙配置，放通以下端口：</p> <p><img alt="" data-src="https://pic.yupi.icu/5563/202311071928933.png" loading="lazy" class="lazy"></p> <p>然后像访问本地服务一样分别去访问 MySQL、Redis、RabbitMQ、Nacos 即可，应该都是成功的。</p> <p><img alt="" data-src="https://pic.yupi.icu/5563/202311071928247.png" loading="lazy" class="lazy"></p> <p>由于进程在前台启动会影响我们的操作，所以先按 <code>ctrl + c</code> 退出，加上 <code>-d</code> 参数让容器在后台启动：</p> <div class="language- line-numbers-mode"><pre class="language-text"><code>sudo docker compose -f docker-compose.env.yml up -d
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br></div></div><p>试着查看下 docker 容器的状态：</p> <div class="language- line-numbers-mode"><pre class="language-text"><code>sudo docker stats
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br></div></div><p>能够查看到所有容器的资源占用情况：</p> <p><img alt="" data-src="https://pic.yupi.icu/5563/202311071928655.png" loading="lazy" class="lazy"></p> <p>实话说，我开始紧张了，不知道 4 G 的内存够不够撑。。。</p> <h4 id="_2-启动业务服务"><a href="#_2-启动业务服务" class="header-anchor">#</a> 2）启动业务服务</h4> <p>确保环境依赖都启动成功后，接下来启动业务服务：</p> <div class="language- line-numbers-mode"><pre class="language-text"><code>docker compose -f docker-compose.service.yml up
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br></div></div><p>项目全部启动，看得很爽：</p> <p><img alt="" data-src="https://pic.yupi.icu/5563/202311071928915.png" loading="lazy" class="lazy"></p> <p>正常来说，应该会启动成功；但如果运气背，可能会有失败，比如我这的网关服务就启动失败了。</p> <p>如果某个服务启动失败，可以再次单独只启动它，比如网关服务：</p> <div class="language- line-numbers-mode"><pre class="language-text"><code>sudo docker compose -f docker-compose.service.yml up yuoj-backend-gateway
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br></div></div><h3 id="_2-6、测试访问"><a href="#_2-6、测试访问" class="header-anchor">#</a> 2.6、测试访问</h3> <p>最后，像验证本地微服务项目部署一样，访问线上网关的接口文档（ http://你的服务器 IP:8101/doc.html ），依次调用用户注册 =&gt; 登录 =&gt; 获取登录用户信息 =&gt; 创建题目，全部成功~</p> <p><img alt="" data-src="https://pic.yupi.icu/5563/202311071928930.png" loading="lazy" class="lazy"></p> <p>最后使用 <code>docker stats</code> 命令查看 Docker 容器的状态，发现总共的内存占用大概 3 G，也就是说 4 G 内存的服务器是完全足够小型微服务项目的部署了~</p> <p><img alt="" data-src="https://pic.yupi.icu/5563/202311071928035.png" loading="lazy" class="lazy"></p> <p>至此，微服务项目部署教程就结束了。</p> <h2 id="最后"><a href="#最后" class="header-anchor">#</a> 最后</h2> <p>最后我再问个问题，如果我只有一台 2 G 内存的服务器，能否成功部署这套有 4 个业务服务的项目呢？如果能的话，又应该怎么部署呢？欢迎大家讨论。</p> <p>下图是个小提示：</p> <p><img alt="" data-src="https://pic.yupi.icu/5563/202311071928269.png" loading="lazy" class="lazy"></p> <p>终于写完了这篇 6000 多字的教程，如果觉得本期内容有帮助的话，也欢迎点赞、收藏三连支持，谢谢大家！</p></div> <footer class="page-edit" style="margin:0;"><div class="edit-link"><a href="https://github.com/liyupi/codefather/edit/master/编程分享/技术分享/技术实践/快速部署微服务项目，保姆级教程.md" target="_blank" rel="noopener noreferrer">完善页面</a> <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></div> <div class="last-updated"><span class="prefix">最近更新:</span> <span class="time">11/11/2023, 8:17:47 PM</span></div></footer> <!----></div> <div class="toc-container-sidebar"><div class="pos-box"><div class="icon-arrow"></div> <div class="scroll-box" style="max-height:86vh"><div style="font-weight:bold;">快速部署微服务项目，保姆级教程</div> <hr> <div class="toc-box"><ul class="toc-sidebar-links"><li><a href="/%E5%BF%AB%E9%80%9F%E9%83%A8%E7%BD%B2%E5%BE%AE%E6%9C%8D%E5%8A%A1%E9%A1%B9%E7%9B%AE-%E4%BF%9D%E5%A7%86%E7%BA%A7%E6%95%99%E7%A8%8B/#项目介绍" class="toc-sidebar-link">项目介绍</a><ul class="toc-sidebar-sub-headers"></ul></li><li><a href="/%E5%BF%AB%E9%80%9F%E9%83%A8%E7%BD%B2%E5%BE%AE%E6%9C%8D%E5%8A%A1%E9%A1%B9%E7%9B%AE-%E4%BF%9D%E5%A7%86%E7%BA%A7%E6%95%99%E7%A8%8B/#传统部署" class="toc-sidebar-link">传统部署</a><ul class="toc-sidebar-sub-headers"></ul></li><li><a href="/%E5%BF%AB%E9%80%9F%E9%83%A8%E7%BD%B2%E5%BE%AE%E6%9C%8D%E5%8A%A1%E9%A1%B9%E7%9B%AE-%E4%BF%9D%E5%A7%86%E7%BA%A7%E6%95%99%E7%A8%8B/#docker-compose-介绍" class="toc-sidebar-link">Docker Compose 介绍</a><ul class="toc-sidebar-sub-headers"></ul></li><li><a href="/%E5%BF%AB%E9%80%9F%E9%83%A8%E7%BD%B2%E5%BE%AE%E6%9C%8D%E5%8A%A1%E9%A1%B9%E7%9B%AE-%E4%BF%9D%E5%A7%86%E7%BA%A7%E6%95%99%E7%A8%8B/#部署流程" class="toc-sidebar-link">部署流程</a><ul class="toc-sidebar-sub-headers"></ul></li><li><a href="/%E5%BF%AB%E9%80%9F%E9%83%A8%E7%BD%B2%E5%BE%AE%E6%9C%8D%E5%8A%A1%E9%A1%B9%E7%9B%AE-%E4%BF%9D%E5%A7%86%E7%BA%A7%E6%95%99%E7%A8%8B/#一、本地部署" class="toc-sidebar-link">一、本地部署</a><ul class="toc-sidebar-sub-headers"><li class="toc-sidebar-sub-header"><a href="/%E5%BF%AB%E9%80%9F%E9%83%A8%E7%BD%B2%E5%BE%AE%E6%9C%8D%E5%8A%A1%E9%A1%B9%E7%9B%AE-%E4%BF%9D%E5%A7%86%E7%BA%A7%E6%95%99%E7%A8%8B/#_1-1、梳理服务部署表格" class="toc-sidebar-link">1.1、梳理服务部署表格</a></li><li class="toc-sidebar-sub-header"><a href="/%E5%BF%AB%E9%80%9F%E9%83%A8%E7%BD%B2%E5%BE%AE%E6%9C%8D%E5%8A%A1%E9%A1%B9%E7%9B%AE-%E4%BF%9D%E5%A7%86%E7%BA%A7%E6%95%99%E7%A8%8B/#_1-2、maven-子父模块打包" class="toc-sidebar-link">1.2、Maven 子父模块打包</a></li><li class="toc-sidebar-sub-header toc-sidebar-depth-4"><a href="/%E5%BF%AB%E9%80%9F%E9%83%A8%E7%BD%B2%E5%BE%AE%E6%9C%8D%E5%8A%A1%E9%A1%B9%E7%9B%AE-%E4%BF%9D%E5%A7%86%E7%BA%A7%E6%95%99%E7%A8%8B/#_1-父模块配置" class="toc-sidebar-link">1）父模块配置</a></li><li class="toc-sidebar-sub-header toc-sidebar-depth-4"><a href="/%E5%BF%AB%E9%80%9F%E9%83%A8%E7%BD%B2%E5%BE%AE%E6%9C%8D%E5%8A%A1%E9%A1%B9%E7%9B%AE-%E4%BF%9D%E5%A7%86%E7%BA%A7%E6%95%99%E7%A8%8B/#_2-子模块配置" class="toc-sidebar-link">2）子模块配置</a></li><li class="toc-sidebar-sub-header"><a href="/%E5%BF%AB%E9%80%9F%E9%83%A8%E7%BD%B2%E5%BE%AE%E6%9C%8D%E5%8A%A1%E9%A1%B9%E7%9B%AE-%E4%BF%9D%E5%A7%86%E7%BA%A7%E6%95%99%E7%A8%8B/#_1-3、dockerfile-编写" class="toc-sidebar-link">1.3、Dockerfile 编写</a></li><li class="toc-sidebar-sub-header toc-sidebar-depth-4"><a href="/%E5%BF%AB%E9%80%9F%E9%83%A8%E7%BD%B2%E5%BE%AE%E6%9C%8D%E5%8A%A1%E9%A1%B9%E7%9B%AE-%E4%BF%9D%E5%A7%86%E7%BA%A7%E6%95%99%E7%A8%8B/#_1-复制-jar-包版" class="toc-sidebar-link">1）复制 jar 包版</a></li><li class="toc-sidebar-sub-header toc-sidebar-depth-4"><a href="/%E5%BF%AB%E9%80%9F%E9%83%A8%E7%BD%B2%E5%BE%AE%E6%9C%8D%E5%8A%A1%E9%A1%B9%E7%9B%AE-%E4%BF%9D%E5%A7%86%E7%BA%A7%E6%95%99%E7%A8%8B/#_2-maven-打包版" class="toc-sidebar-link">2）Maven 打包版</a></li><li class="toc-sidebar-sub-header"><a href="/%E5%BF%AB%E9%80%9F%E9%83%A8%E7%BD%B2%E5%BE%AE%E6%9C%8D%E5%8A%A1%E9%A1%B9%E7%9B%AE-%E4%BF%9D%E5%A7%86%E7%BA%A7%E6%95%99%E7%A8%8B/#_1-4、编写环境依赖配置" class="toc-sidebar-link">1.4、编写环境依赖配置</a></li><li class="toc-sidebar-sub-header toc-sidebar-depth-4"><a href="/%E5%BF%AB%E9%80%9F%E9%83%A8%E7%BD%B2%E5%BE%AE%E6%9C%8D%E5%8A%A1%E9%A1%B9%E7%9B%AE-%E4%BF%9D%E5%A7%86%E7%BA%A7%E6%95%99%E7%A8%8B/#_1-mysql" class="toc-sidebar-link">1）MySQL</a></li><li class="toc-sidebar-sub-header toc-sidebar-depth-4"><a href="/%E5%BF%AB%E9%80%9F%E9%83%A8%E7%BD%B2%E5%BE%AE%E6%9C%8D%E5%8A%A1%E9%A1%B9%E7%9B%AE-%E4%BF%9D%E5%A7%86%E7%BA%A7%E6%95%99%E7%A8%8B/#_2-redis" class="toc-sidebar-link">2）Redis</a></li><li class="toc-sidebar-sub-header toc-sidebar-depth-4"><a href="/%E5%BF%AB%E9%80%9F%E9%83%A8%E7%BD%B2%E5%BE%AE%E6%9C%8D%E5%8A%A1%E9%A1%B9%E7%9B%AE-%E4%BF%9D%E5%A7%86%E7%BA%A7%E6%95%99%E7%A8%8B/#_3-rabbitmq" class="toc-sidebar-link">3）RabbitMQ</a></li><li class="toc-sidebar-sub-header toc-sidebar-depth-4"><a href="/%E5%BF%AB%E9%80%9F%E9%83%A8%E7%BD%B2%E5%BE%AE%E6%9C%8D%E5%8A%A1%E9%A1%B9%E7%9B%AE-%E4%BF%9D%E5%A7%86%E7%BA%A7%E6%95%99%E7%A8%8B/#_4-nacos" class="toc-sidebar-link">4）Nacos</a></li><li class="toc-sidebar-sub-header toc-sidebar-depth-4"><a href="/%E5%BF%AB%E9%80%9F%E9%83%A8%E7%BD%B2%E5%BE%AE%E6%9C%8D%E5%8A%A1%E9%A1%B9%E7%9B%AE-%E4%BF%9D%E5%A7%86%E7%BA%A7%E6%95%99%E7%A8%8B/#完整-docker-compose-文件" class="toc-sidebar-link">完整 Docker Compose 文件</a></li><li class="toc-sidebar-sub-header"><a href="/%E5%BF%AB%E9%80%9F%E9%83%A8%E7%BD%B2%E5%BE%AE%E6%9C%8D%E5%8A%A1%E9%A1%B9%E7%9B%AE-%E4%BF%9D%E5%A7%86%E7%BA%A7%E6%95%99%E7%A8%8B/#_1-5、编写业务服务配置" class="toc-sidebar-link">1.5、编写业务服务配置</a></li><li class="toc-sidebar-sub-header"><a href="/%E5%BF%AB%E9%80%9F%E9%83%A8%E7%BD%B2%E5%BE%AE%E6%9C%8D%E5%8A%A1%E9%A1%B9%E7%9B%AE-%E4%BF%9D%E5%A7%86%E7%BA%A7%E6%95%99%E7%A8%8B/#_1-6、调整程序配置" class="toc-sidebar-link">1.6、调整程序配置</a></li><li class="toc-sidebar-sub-header"><a href="/%E5%BF%AB%E9%80%9F%E9%83%A8%E7%BD%B2%E5%BE%AE%E6%9C%8D%E5%8A%A1%E9%A1%B9%E7%9B%AE-%E4%BF%9D%E5%A7%86%E7%BA%A7%E6%95%99%E7%A8%8B/#_1-7、测试访问" class="toc-sidebar-link">1.7、测试访问</a></li></ul></li><li><a href="/%E5%BF%AB%E9%80%9F%E9%83%A8%E7%BD%B2%E5%BE%AE%E6%9C%8D%E5%8A%A1%E9%A1%B9%E7%9B%AE-%E4%BF%9D%E5%A7%86%E7%BA%A7%E6%95%99%E7%A8%8B/#二、服务器部署" class="toc-sidebar-link">二、服务器部署</a><ul class="toc-sidebar-sub-headers"><li class="toc-sidebar-sub-header"><a href="/%E5%BF%AB%E9%80%9F%E9%83%A8%E7%BD%B2%E5%BE%AE%E6%9C%8D%E5%8A%A1%E9%A1%B9%E7%9B%AE-%E4%BF%9D%E5%A7%86%E7%BA%A7%E6%95%99%E7%A8%8B/#_2-1、准备服务器" class="toc-sidebar-link">2.1、准备服务器</a></li><li class="toc-sidebar-sub-header"><a href="/%E5%BF%AB%E9%80%9F%E9%83%A8%E7%BD%B2%E5%BE%AE%E6%9C%8D%E5%8A%A1%E9%A1%B9%E7%9B%AE-%E4%BF%9D%E5%A7%86%E7%BA%A7%E6%95%99%E7%A8%8B/#_2-2、docker-compose-安装" class="toc-sidebar-link">2.2、Docker Compose 安装</a></li><li class="toc-sidebar-sub-header"><a href="/%E5%BF%AB%E9%80%9F%E9%83%A8%E7%BD%B2%E5%BE%AE%E6%9C%8D%E5%8A%A1%E9%A1%B9%E7%9B%AE-%E4%BF%9D%E5%A7%86%E7%BA%A7%E6%95%99%E7%A8%8B/#_2-3、同步文件" class="toc-sidebar-link">2.3、同步文件</a></li><li class="toc-sidebar-sub-header"><a href="/%E5%BF%AB%E9%80%9F%E9%83%A8%E7%BD%B2%E5%BE%AE%E6%9C%8D%E5%8A%A1%E9%A1%B9%E7%9B%AE-%E4%BF%9D%E5%A7%86%E7%BA%A7%E6%95%99%E7%A8%8B/#_2-4、获取-jar-包" class="toc-sidebar-link">2.4、获取 jar 包</a></li><li class="toc-sidebar-sub-header"><a href="/%E5%BF%AB%E9%80%9F%E9%83%A8%E7%BD%B2%E5%BE%AE%E6%9C%8D%E5%8A%A1%E9%A1%B9%E7%9B%AE-%E4%BF%9D%E5%A7%86%E7%BA%A7%E6%95%99%E7%A8%8B/#_2-5、服务启动" class="toc-sidebar-link">2.5、服务启动</a></li><li class="toc-sidebar-sub-header toc-sidebar-depth-4"><a href="/%E5%BF%AB%E9%80%9F%E9%83%A8%E7%BD%B2%E5%BE%AE%E6%9C%8D%E5%8A%A1%E9%A1%B9%E7%9B%AE-%E4%BF%9D%E5%A7%86%E7%BA%A7%E6%95%99%E7%A8%8B/#_1-启动环境依赖" class="toc-sidebar-link">1）启动环境依赖</a></li><li class="toc-sidebar-sub-header toc-sidebar-depth-4"><a href="/%E5%BF%AB%E9%80%9F%E9%83%A8%E7%BD%B2%E5%BE%AE%E6%9C%8D%E5%8A%A1%E9%A1%B9%E7%9B%AE-%E4%BF%9D%E5%A7%86%E7%BA%A7%E6%95%99%E7%A8%8B/#_2-启动业务服务" class="toc-sidebar-link">2）启动业务服务</a></li><li class="toc-sidebar-sub-header"><a href="/%E5%BF%AB%E9%80%9F%E9%83%A8%E7%BD%B2%E5%BE%AE%E6%9C%8D%E5%8A%A1%E9%A1%B9%E7%9B%AE-%E4%BF%9D%E5%A7%86%E7%BA%A7%E6%95%99%E7%A8%8B/#_2-6、测试访问" class="toc-sidebar-link">2.6、测试访问</a></li></ul></li><li><a href="/%E5%BF%AB%E9%80%9F%E9%83%A8%E7%BD%B2%E5%BE%AE%E6%9C%8D%E5%8A%A1%E9%A1%B9%E7%9B%AE-%E4%BF%9D%E5%A7%86%E7%BA%A7%E6%95%99%E7%A8%8B/#最后" class="toc-sidebar-link">最后</a><ul class="toc-sidebar-sub-headers"></ul></li></ul></div></div></div></div></div>  <main class="footer"> <div class="copy-right"><span class="name"> 编程导航   |     </span> <a target="_blank" rel="noreferrer">
          
        </a></div></main></main> <aside class="page-sidebar"> <div class="page-side-toolbar"></div>  </aside></div><div class="global-ui"><!----></div></div>
    <script src="/assets/js/app.12ab4756.js" defer></script><script src="/assets/js/2.fd06b53e.js" defer></script><script src="/assets/js/265.be8d1ee8.js" defer></script>
  </body>
</html>
